struct EvalStatus {
/// Whether the evaluated expression has side effects.
/// For example, (f() && 0) can be folded, but it still has side effects.
- bool HasSideEffects;
+ bool HasSideEffects = false;
/// Whether the evaluation hit undefined behavior.
/// For example, 1.0 / 0.0 can be folded to Inf, but has undefined behavior.
/// Likewise, INT_MAX + 1 can be folded to INT_MIN, but has UB.
- bool HasUndefinedBehavior;
+ bool HasUndefinedBehavior = false;
/// Diag - If this is non-null, it will be filled in with a stack of notes
/// indicating why evaluation failed (or why it failed to produce a constant
/// foldable. If the expression is foldable, but not a constant expression,
/// the notes will describes why it isn't a constant expression. If the
/// expression *is* a constant expression, no notes will be produced.
- SmallVectorImpl<PartialDiagnosticAt> *Diag;
-
- EvalStatus()
- : HasSideEffects(false), HasUndefinedBehavior(false), Diag(nullptr) {}
+ SmallVectorImpl<PartialDiagnosticAt> *Diag = nullptr;
// hasSideEffects - Return true if the evaluated expression has
// side effects.
/// EvalResult is a struct with detailed info about an evaluated expression.
struct EvalResult : EvalStatus {
- /// Val - This is the value the expression can be folded to.
+ /// This is the value the expression can be folded to.
APValue Val;
+ /// Indicates whether Val contains a pointer or reference or pointer to
+ /// member naming a templated entity, and thus the value is dependent.
+ bool Dependent = false;
// isGlobalLValue - Return true if the evaluated lvalue expression
// is global.
/// Whether this template argument is dependent on a template
/// parameter such that its result can change from one instantiation to
/// another.
+ ///
+ /// It's not always meaningful to ask whether a template argument is
+ /// dependent before it's been converted to match a template parameter;
+ /// whether a non-type template argument is dependent depends on the
+ /// corresponding parameter. For an unconverted template argument, this
+ /// returns true if the argument *might* be dependent.
bool isDependent() const;
/// Whether this template argument is dependent on a template
void initializeFrom(SourceLocation TemplateKWLoc,
const TemplateArgumentListInfo &List,
TemplateArgumentLoc *OutArgArray);
- // FIXME: The parameter Deps is the result populated by this method, the
- // caller doesn't need it since it is populated by computeDependence. remove
- // it.
- void initializeFrom(SourceLocation TemplateKWLoc,
- const TemplateArgumentListInfo &List,
- TemplateArgumentLoc *OutArgArray,
- TemplateArgumentDependence &Deps);
void initializeFrom(SourceLocation TemplateKWLoc);
void copyInto(const TemplateArgumentLoc *ArgArray,
llvm::APSInt &Value, CCEKind CCE);
ExprResult CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
- NamedDecl *Dest = nullptr);
+ NamedDecl *Dest = nullptr,
+ bool *ValueDependent = nullptr);
/// Abstract base class used to perform a contextual implicit
/// conversion from an expression to any type passing a filter.
if (VD && VD->isTemplated()) {
auto *VarD = dyn_cast<VarDecl>(VD);
if (!VarD || !VarD->hasLocalStorage())
- Dep |= ExprDependence::Value;
+ Dep |= ExprDependence::ValueInstantiation;
}
}
}
if (auto *FirstArg = E->getTemplateArgs()) {
unsigned NumArgs = E->getNumTemplateArgs();
for (auto *Arg = FirstArg, *End = FirstArg + NumArgs; Arg < End; ++Arg)
- Deps |= toExprDependence(Arg->getArgument().getDependence());
+ Deps |= toExprDependence(Arg->getArgument().getDependence() &
+ ~TemplateArgumentDependence::Dependent);
}
auto *Decl = E->getDecl();
+ auto *Found = E->getFoundDecl();
auto Type = E->getType();
+ // FIXME: For a ParmVarDecl referenced in a function signature, we don't know
+ // its dependence yet!
+ if (!isa<ParmVarDecl>(Decl)) {
+ if (Decl->getDeclContext()->isDependentContext() ||
+ (Found && Found->getDeclContext()->isDependentContext()))
+ Deps |= ExprDependence::Instantiation;
+ }
if (Decl->isParameterPack())
Deps |= ExprDependence::UnexpandedPack;
Deps |= toExprDependence(Type->getDependence()) & ExprDependence::Error;
RefersToEnclosingVariableOrCapture;
DeclRefExprBits.NonOdrUseReason = NOUR;
if (TemplateArgs) {
- auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
- Deps);
- assert(!(Deps & TemplateArgumentDependence::Dependent) &&
- "built a DeclRefExpr with dependent template args");
+ TemplateKWLoc, *TemplateArgs,
+ getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
NameInfo, T, VK, OK, NOUR);
- // FIXME: remove remaining dependence computation to computeDependence().
- auto Deps = E->getDependence();
+ // FIXME: Move this into the constructor.
if (HasQualOrFound) {
- // FIXME: Wrong. We should be looking at the member declaration we found.
- if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent())
- Deps |= ExprDependence::TypeValueInstantiation;
- else if (QualifierLoc &&
- QualifierLoc.getNestedNameSpecifier()->isInstantiationDependent())
- Deps |= ExprDependence::Instantiation;
-
E->MemberExprBits.HasQualifierOrFoundDecl = true;
MemberExprNameQualifier *NQ =
TemplateArgs || TemplateKWLoc.isValid();
if (TemplateArgs) {
- auto TemplateArgDeps = TemplateArgumentDependence::None;
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc, *TemplateArgs,
- E->getTrailingObjects<TemplateArgumentLoc>(), TemplateArgDeps);
- if (TemplateArgDeps & TemplateArgumentDependence::Instantiation)
- Deps |= ExprDependence::Instantiation;
+ E->getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
E->getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
}
+
+ // FIXME: remove remaining dependence computation to computeDependence().
+ auto Deps = E->getDependence();
+ if (NestedNameSpecifier *Qual = E->getQualifier()) {
+ // FIXME: Wrong. We should be looking at the member declaration we found.
+ if (Qual->isDependent())
+ Deps |= ExprDependence::TypeValueInstantiation;
+ else if (Qual->isInstantiationDependent())
+ Deps |= ExprDependence::Instantiation;
+ }
+ if (TemplateSpecializationType::anyInstantiationDependentTemplateArguments(
+ E->template_arguments()))
+ Deps |= ExprDependence::Instantiation;
E->setDependence(Deps);
return E;
}
if (TemplateArgs) {
- auto Deps = TemplateArgumentDependence::None;
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(
- TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc(), Deps);
+ TemplateKWLoc, *TemplateArgs, getTrailingTemplateArgumentLoc());
} else if (TemplateKWLoc.isValid()) {
getTrailingASTTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc);
}
DependentScopeDeclRefExprBits.HasTemplateKWAndArgsInfo =
(Args != nullptr) || TemplateKWLoc.isValid();
if (Args) {
- auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>(), Deps);
+ TemplateKWLoc, *Args, getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
CXXDependentScopeMemberExprBits.OperatorLoc = OperatorLoc;
if (TemplateArgs) {
- auto Deps = TemplateArgumentDependence::None;
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
- TemplateKWLoc, *TemplateArgs, getTrailingObjects<TemplateArgumentLoc>(),
- Deps);
+ TemplateKWLoc, *TemplateArgs,
+ getTrailingObjects<TemplateArgumentLoc>());
} else if (TemplateKWLoc.isValid()) {
getTrailingObjects<ASTTemplateKWAndArgsInfo>()->initializeFrom(
TemplateKWLoc);
static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
static bool EvaluateAtomic(const Expr *E, const LValue *This, APValue &Result,
EvalInfo &Info);
-static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result);
+static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result,
+ bool &Dependent);
/// Evaluate an integer or fixed point expression into an APResult.
static bool EvaluateFixedPointOrInteger(const Expr *E, APFixedPoint &Result,
QualType Type, const APValue &Value,
ConstantExprKind Kind,
SourceLocation SubobjectLoc,
- CheckedTemporaries &CheckedTemps);
+ CheckedTemporaries &CheckedTemps,
+ bool &Dependent);
/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Return true if we
static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
QualType Type, const LValue &LVal,
ConstantExprKind Kind,
- CheckedTemporaries &CheckedTemps) {
+ CheckedTemporaries &CheckedTemps,
+ bool &Dependent) {
bool IsReferenceType = Type->isReferenceType();
APValue::LValueBase Base = LVal.getLValueBase();
}
if (BaseVD) {
+ Dependent |= BaseVD->isTemplated();
+
if (const VarDecl *Var = dyn_cast<const VarDecl>(BaseVD)) {
// Check if this is a thread-local variable.
if (Var->getTLSKind())
}
} else if (const auto *MTE =
dyn_cast_or_null<MaterializeTemporaryExpr>(BaseE)) {
+ if (auto *Extending = MTE->getExtendingDecl())
+ Dependent |= Extending->isTemplated();
+
if (CheckedTemps.insert(MTE).second) {
QualType TempType = getType(Base);
if (TempType.isDestructedType()) {
APValue *V = MTE->getOrCreateValue(false);
assert(V && "evasluation result refers to uninitialised temporary");
if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
- Info, MTE->getExprLoc(), TempType, *V,
- Kind, SourceLocation(), CheckedTemps))
+ Info, MTE->getExprLoc(), TempType, *V, Kind,
+ SourceLocation(), CheckedTemps, Dependent))
return false;
}
}
/// Member pointers are constant expressions unless they point to a
/// non-virtual dllimport member function.
-static bool CheckMemberPointerConstantExpression(EvalInfo &Info,
- SourceLocation Loc,
- QualType Type,
- const APValue &Value,
- ConstantExprKind Kind) {
+static bool
+CheckMemberPointerConstantExpression(EvalInfo &Info, SourceLocation Loc,
+ QualType Type, const APValue &Value,
+ ConstantExprKind Kind, bool &Dependent) {
const ValueDecl *Member = Value.getMemberPointerDecl();
- const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member);
+ if (!Member)
+ return true;
+ Dependent |= Member->isTemplated();
+ const auto *FD = dyn_cast<CXXMethodDecl>(Member);
if (!FD)
return true;
if (FD->isConsteval()) {
QualType Type, const APValue &Value,
ConstantExprKind Kind,
SourceLocation SubobjectLoc,
- CheckedTemporaries &CheckedTemps) {
+ CheckedTemporaries &CheckedTemps,
+ bool &Dependent) {
if (!Value.hasValue()) {
Info.FFDiag(DiagLoc, diag::note_constexpr_uninitialized)
<< true << Type;
for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayInitializedElt(I), Kind,
- SubobjectLoc, CheckedTemps))
+ SubobjectLoc, CheckedTemps, Dependent))
return false;
}
if (!Value.hasArrayFiller())
return true;
return CheckEvaluationResult(CERK, Info, DiagLoc, EltTy,
Value.getArrayFiller(), Kind, SubobjectLoc,
- CheckedTemps);
+ CheckedTemps, Dependent);
}
if (Value.isUnion() && Value.getUnionField()) {
return CheckEvaluationResult(
CERK, Info, DiagLoc, Value.getUnionField()->getType(),
Value.getUnionValue(), Kind, Value.getUnionField()->getLocation(),
- CheckedTemps);
+ CheckedTemps, Dependent);
}
if (Value.isStruct()) {
RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
for (const CXXBaseSpecifier &BS : CD->bases()) {
if (!CheckEvaluationResult(CERK, Info, DiagLoc, BS.getType(),
Value.getStructBase(BaseIndex), Kind,
- BS.getBeginLoc(), CheckedTemps))
+ BS.getBeginLoc(), CheckedTemps, Dependent))
return false;
++BaseIndex;
}
continue;
if (!CheckEvaluationResult(CERK, Info, DiagLoc, I->getType(),
- Value.getStructField(I->getFieldIndex()),
- Kind, I->getLocation(), CheckedTemps))
+ Value.getStructField(I->getFieldIndex()), Kind,
+ I->getLocation(), CheckedTemps, Dependent))
return false;
}
}
LValue LVal;
LVal.setFrom(Info.Ctx, Value);
return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal, Kind,
- CheckedTemps);
+ CheckedTemps, Dependent);
}
if (Value.isMemberPointer() &&
CERK == CheckEvaluationResultKind::ConstantExpression)
- return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value, Kind);
+ return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value,
+ Kind, Dependent);
// Everything else is fine.
return true;
/// check that the expression is of literal type.
static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value,
- ConstantExprKind Kind) {
+ ConstantExprKind Kind, bool &Dependent) {
// Nothing to check for a constant expression of type 'cv void'.
if (Type->isVoidType())
return true;
CheckedTemporaries CheckedTemps;
return CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression,
Info, DiagLoc, Type, Value, Kind,
- SourceLocation(), CheckedTemps);
+ SourceLocation(), CheckedTemps, Dependent);
}
/// Check that this evaluated value is fully-initialized and can be loaded by
/// an lvalue-to-rvalue conversion.
static bool CheckFullyInitialized(EvalInfo &Info, SourceLocation DiagLoc,
QualType Type, const APValue &Value) {
+ bool Dependent = false;
CheckedTemporaries CheckedTemps;
return CheckEvaluationResult(
CheckEvaluationResultKind::FullyInitialized, Info, DiagLoc, Type, Value,
- ConstantExprKind::Normal, SourceLocation(), CheckedTemps);
+ ConstantExprKind::Normal, SourceLocation(), CheckedTemps, Dependent);
}
/// Enforce C++2a [expr.const]/4.17, which disallows new-expressions unless
ArgType->isAnyComplexType() || ArgType->isPointerType() ||
ArgType->isNullPtrType()) {
APValue V;
- if (!::EvaluateAsRValue(Info, Arg, V) || Info.EvalStatus.HasSideEffects) {
+ bool Dependent = false;
+ if (!::EvaluateAsRValue(Info, Arg, V, Dependent) ||
+ Info.EvalStatus.HasSideEffects) {
Fold.keepDiagnostics();
return false;
}
// It's possible for us to be given GLValues if we're called via
// Expr::tryEvaluateObjectSize.
APValue RVal;
- if (!EvaluateAsRValue(Info, E, RVal))
+ bool Dependent = false;
+ if (!EvaluateAsRValue(Info, E, RVal, Dependent))
return false;
LVal.setFrom(Info.Ctx, RVal);
} else if (!EvaluatePointer(ignorePointerCastsAndParens(E), LVal, Info,
LV.set(VD);
if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result))
return false;
+ bool Dependent = false;
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
- ConstantExprKind::Normal);
+ ConstantExprKind::Normal, Dependent);
};
return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() {
return ExprEvaluatorBaseTy::VisitBinCmp(E);
/// EvaluateAsRValue - Try to evaluate this expression, performing an implicit
/// lvalue-to-rvalue cast if it is an lvalue.
-static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) {
+static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result,
+ bool &Dependent) {
assert(!E->isValueDependent());
if (Info.EnableNewConstInterp) {
if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result))
// Check this core constant expression is a constant expression.
return CheckConstantExpression(Info, E->getExprLoc(), E->getType(), Result,
- ConstantExprKind::Normal) &&
+ ConstantExprKind::Normal, Dependent) &&
CheckMemoryLeaks(Info);
}
if (FastEvaluateAsRValue(E, Result, Ctx, IsConst))
return IsConst;
- return EvaluateAsRValue(Info, E, Result.Val);
+ return EvaluateAsRValue(Info, E, Result.Val, Result.Dependent);
}
static bool EvaluateAsInt(const Expr *E, Expr::EvalResult &ExprResult,
CheckedTemporaries CheckedTemps;
if (!EvaluateLValue(this, LV, Info) || !Info.discardCleanups() ||
Result.HasSideEffects ||
- !CheckLValueConstantExpression(Info, getExprLoc(),
- Ctx.getLValueReferenceType(getType()), LV,
- ConstantExprKind::Normal, CheckedTemps))
+ !CheckLValueConstantExpression(
+ Info, getExprLoc(), Ctx.getLValueReferenceType(getType()), LV,
+ ConstantExprKind::Normal, CheckedTemps, Result.Dependent))
return false;
LV.moveInto(Result.Val);
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
if (!CheckConstantExpression(Info, getExprLoc(), getStorageType(Ctx, this),
- Result.Val, Kind))
+ Result.Val, Kind, Result.Dependent))
return false;
if (!CheckMemoryLeaks(Info))
return false;
if (!Info.discardCleanups())
llvm_unreachable("Unhandled cleanup; missing full expression marker?");
}
+ bool Dependent = false;
return CheckConstantExpression(Info, DeclLoc, DeclTy, Value,
- ConstantExprKind::Normal) &&
+ ConstantExprKind::Normal, Dependent) &&
CheckMemoryLeaks(Info);
}
Info.InConstantContext = true;
Info.CheckingForUndefinedBehavior = true;
- bool Result = ::EvaluateAsRValue(Info, this, EVResult.Val);
+ bool Result = ::EvaluateAsRValue(this, EVResult, Ctx, Info);
(void)Result;
assert(Result && "Could not evaluate expression");
assert(EVResult.Val.isInt() && "Expression did not evaluate to integer");
assert(!isValueDependent() &&
"Expression evaluator can't be called on a dependent expression.");
- bool IsConst;
EvalResult EVResult;
- if (!FastEvaluateAsRValue(this, EVResult, Ctx, IsConst)) {
- EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
- Info.CheckingForUndefinedBehavior = true;
- (void)::EvaluateAsRValue(Info, this, EVResult.Val);
- }
+ EvalInfo Info(Ctx, EVResult, EvalInfo::EM_IgnoreSideEffects);
+ Info.CheckingForUndefinedBehavior = true;
+ (void)::EvaluateAsRValue(this, EVResult, Ctx, Info);
}
bool Expr::EvalResult::isGlobalLValue() const {
EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression);
APValue Scratch;
+ bool Dependent = false;
bool IsConstExpr =
- ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch) &&
+ ::EvaluateAsRValue(Info, this, Result ? *Result : Scratch, Dependent) &&
// FIXME: We don't produce a diagnostic for this, but the callers that
// call us on arbitrary full-expressions should generally not care.
Info.discardCleanups() && !Status.HasSideEffects;
return TemplateArgumentDependence::Dependent |
TemplateArgumentDependence::Instantiation;
- case Declaration: {
- auto *DC = dyn_cast<DeclContext>(getAsDecl());
- if (!DC)
- DC = getAsDecl()->getDeclContext();
- if (DC->isDependentContext())
- Deps = TemplateArgumentDependence::Dependent |
- TemplateArgumentDependence::Instantiation;
- return Deps;
- }
-
case NullPtr:
case Integral:
+ case Declaration:
return TemplateArgumentDependence::None;
case Expression:
Deps = toTemplateArgumentDependence(getAsExpr()->getDependence());
- if (isa<PackExpansionExpr>(getAsExpr()))
- Deps |= TemplateArgumentDependence::Dependent |
- TemplateArgumentDependence::Instantiation;
+ // Instantiation-dependent expression arguments are considered dependent
+ // until they're resolved to another form.
+ if (Deps & TemplateArgumentDependence::Instantiation)
+ Deps |= TemplateArgumentDependence::Dependent;
return Deps;
case Pack:
NumTemplateArgs = Info.size();
TemplateArgumentLoc *ArgBuffer = getTrailingObjects<TemplateArgumentLoc>();
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
+ std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
+ ArgBuffer);
}
void ASTTemplateKWAndArgsInfo::initializeFrom(
LAngleLoc = Info.getLAngleLoc();
RAngleLoc = Info.getRAngleLoc();
NumTemplateArgs = Info.size();
-
- for (unsigned i = 0; i != NumTemplateArgs; ++i)
- new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
+ std::uninitialized_copy(Info.arguments().begin(), Info.arguments().end(),
+ OutArgArray);
}
void ASTTemplateKWAndArgsInfo::initializeFrom(SourceLocation TemplateKWLoc) {
NumTemplateArgs = 0;
}
-void ASTTemplateKWAndArgsInfo::initializeFrom(
- SourceLocation TemplateKWLoc, const TemplateArgumentListInfo &Info,
- TemplateArgumentLoc *OutArgArray, TemplateArgumentDependence &Deps) {
- this->TemplateKWLoc = TemplateKWLoc;
- LAngleLoc = Info.getLAngleLoc();
- RAngleLoc = Info.getRAngleLoc();
- NumTemplateArgs = Info.size();
-
- for (unsigned i = 0; i != NumTemplateArgs; ++i) {
- Deps |= Info[i].getArgument().getDependence();
-
- new (&OutArgArray[i]) TemplateArgumentLoc(Info[i]);
- }
-}
-
void ASTTemplateKWAndArgsInfo::copyInto(const TemplateArgumentLoc *ArgArray,
TemplateArgumentListInfo &Info) const {
Info.setLAngleLoc(LAngleLoc);
QualType T, APValue &Value,
Sema::CCEKind CCE,
bool RequireInt,
- NamedDecl *Dest) {
+ NamedDecl *Dest,
+ bool *ValueDependent) {
assert(S.getLangOpts().CPlusPlus11 &&
"converted constant expression outside C++11");
if (Result.get()->isValueDependent()) {
Value = APValue();
+ if (ValueDependent)
+ *ValueDependent = true;
return Result;
}
Result = ExprError();
} else {
Value = Eval.Val;
+ if (ValueDependent)
+ *ValueDependent = Eval.Dependent;
if (Notes.empty()) {
// It's a constant expression.
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue &Value, CCEKind CCE,
- NamedDecl *Dest) {
+ NamedDecl *Dest,
+ bool *ValueDependent) {
return ::CheckConvertedConstantExpression(*this, From, T, Value, CCE, false,
- Dest);
+ Dest, ValueDependent);
}
ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T,
APValue V;
auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true,
- /*Dest=*/nullptr);
+ /*Dest=*/nullptr,
+ /*ValueDependent=*/nullptr);
if (!R.isInvalid() && !R.get()->isValueDependent())
Value = V.getInt();
return R;
Arg, ArgType))
return true;
+ // Don't build a resolved template argument naming a dependent declaration.
+ if (Entity->isTemplated()) {
+ Converted = TemplateArgument(ArgIn);
+ return false;
+ }
+
// Create the template argument.
Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()),
S.Context.getCanonicalType(ParamType));
QualType ParamType,
Expr *&ResultArg,
TemplateArgument &Converted) {
- bool Invalid = false;
-
Expr *Arg = ResultArg;
bool ObjCLifetimeConversion;
// See http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#773
bool ExtraParens = false;
while (ParenExpr *Parens = dyn_cast<ParenExpr>(Arg)) {
- if (!Invalid && !ExtraParens) {
+ if (!ExtraParens) {
S.Diag(Arg->getBeginLoc(),
S.getLangOpts().CPlusPlus11
? diag::warn_cxx98_compat_template_arg_extra_parens
ValueDecl *VD = DRE->getDecl();
if (VD->getType()->isMemberPointerType()) {
if (isa<NonTypeTemplateParmDecl>(VD)) {
- if (Arg->isTypeDependent() || Arg->isValueDependent()) {
- Converted = TemplateArgument(Arg);
- } else {
- VD = cast<ValueDecl>(VD->getCanonicalDecl());
- Converted = TemplateArgument(VD, ParamType);
- }
- return Invalid;
+ Converted = TemplateArgument(Arg);
+ return false;
}
}
ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl());
Converted = TemplateArgument(D, S.Context.getCanonicalType(ParamType));
}
- return Invalid;
+ return false;
}
// We found something else, but we don't know specifically what it is.
// A template-argument for a non-type template parameter shall be
// a converted constant expression of the type of the template-parameter.
APValue Value;
+ bool ValueDependent = false;
ExprResult ArgResult = CheckConvertedConstantExpression(
- Arg, ParamType, Value, CCEK_TemplateArg, Param);
+ Arg, ParamType, Value, CCEK_TemplateArg, Param, &ValueDependent);
if (ArgResult.isInvalid())
return ExprError();
// For a value-dependent argument, CheckConvertedConstantExpression is
- // permitted (and expected) to be unable to determine a value.
- if (ArgResult.get()->isValueDependent()) {
+ // permitted (and expected) to be unable to determine a value. We might find
+ // the evaluated result refers to a dependent declaration even though the
+ // template argument is not a value-dependent expression.
+ if (ValueDependent) {
Converted = TemplateArgument(ArgResult.get());
return ArgResult;
}
if (FunctionDecl *Pattern =
Function->getInstantiatedFromMemberFunction()) {
- if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
+ if (TSK != TSK_ImplicitInstantiation &&
+ Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
MemberSpecializationInfo *MSInfo =
continue;
if (Var->isStaticDataMember()) {
- if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
+ if (TSK != TSK_ImplicitInstantiation &&
+ Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
continue;
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
SuppressNew)
continue;
- if (TSK == TSK_ExplicitInstantiationDefinition) {
+ if (TSK != TSK_ExplicitInstantiationDeclaration) {
// C++0x [temp.explicit]p8:
// An explicit instantiation definition that names a class template
// specialization explicitly instantiates the class template
for (int i = 0; i < 10; ++i) foo();
#pragma omp distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
- #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+ #pragma omp distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
#pragma omp teams
-#pragma omp distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
}
#pragma omp target parallel for simd collapse (S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
+ // expected-error@+1 1+{{integral constant expression}} expected-note@+1 0+{{constant expression}}
#pragma omp target parallel for simd collapse (j=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp target parallel for simd collapse (1)
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
-// expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
+// expected-error@+1 {{'ordered' clause with a parameter can not be specified in '#pragma omp target parallel for simd' directive}}
#pragma omp target parallel for simd ordered(j = 2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++)
argv[0][i] = argv[0][i] - argv[0][i - ST];
#pragma omp target simd collapse (S) // expected-error {{'S' does not refer to a value}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
- // expected-error@+1 {{integral constant expression}} expected-note@+1 0+{{constant expression}}
+ // expected-error@+1 1+{{integral constant expression}} expected-note@+1 0+{{constant expression}}
#pragma omp target simd collapse (j=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
for (int i = ST; i < N; i++) argv[0][i] = argv[0][i] - argv[0][i-ST];
#pragma omp target simd collapse (1)
#pragma omp target teams distribute dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
-#pragma omp target teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp target teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#pragma omp target teams distribute parallel for dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
-#pragma omp target teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp target teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#pragma omp target teams distribute parallel for simd dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
-#pragma omp target teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp target teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#pragma omp target teams distribute simd dist_schedule (static, S1) // expected-error {{'S1' does not refer to a value}}
for (int i = 0; i < 10; ++i) foo();
-#pragma omp target teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp target teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
#pragma omp target update from(x, s7.s6[:5].aa[6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update from(x, s7.s6[:5].aa[:6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update from(s7.p[:10])
-#pragma omp target update from(x, s7.bfa) // expected-error {{bit fields cannot be used to specify storage in a 'from' clause}}
+#pragma omp target update from(x, s7.bfa) // expected-error 2{{bit fields cannot be used to specify storage in a 'from' clause}}
#pragma omp target update from(x, s7.p[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
#pragma omp target data map(to: s7.i)
{
#pragma omp target update to(x, s7.s6[:5].aa[6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update to(x, s7.s6[:5].aa[:6]) // expected-error {{OpenMP array section is not allowed here}}
#pragma omp target update to(s7.p[:10])
-#pragma omp target update to(x, s7.bfa) // expected-error {{bit fields cannot be used to specify storage in a 'to' clause}}
+#pragma omp target update to(x, s7.bfa) // expected-error 2{{bit fields cannot be used to specify storage in a 'to' clause}}
#pragma omp target update to(x, s7.p[:]) // expected-error {{section length is unspecified and cannot be inferred because subscripted value is not an array}}
#pragma omp target data map(to: s7.i)
{
#pragma omp task detach(a) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'int'}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'S'}}
;
#pragma omp task detach(evt) detach(evt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}}
-#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'const omp_event_handle_t' (aka 'const unsigned long')}} omp50-error {{expected variable of the 'omp_event_handle_t' type, not 'omp_event_handle_t &' (aka 'unsigned long &')}}
+#pragma omp task detach(cevt) detach(revt) // omp45-error 2 {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} expected-error {{directive '#pragma omp task' cannot contain more than one 'detach' clause}}
#pragma omp task detach(evt) mergeable // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'mergeable' and 'detach' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'detach' clause is specified here}}
;
#pragma omp task mergeable detach(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{'detach' and 'mergeable' clause are mutually exclusive and may not appear on the same directive}} omp50-note {{'mergeable' clause is specified here}}
-#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}} omp50-error {{expected variable of the 'omp_event_handle_t' type}}
+#pragma omp task detach(-evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
;
#pragma omp task detach(evt) shared(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
#pragma omp task detach(evt) firstprivate(evt) // omp45-error {{unexpected OpenMP clause 'detach' in directive '#pragma omp task'}}
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
-#pragma omp teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp teams distribute dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
-#pragma omp teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp teams distribute parallel for dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
-#pragma omp teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp teams distribute parallel for simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
for (int i = 0; i < 10; ++i) foo();
#pragma omp target
-#pragma omp teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error3 {{expression must have integral or unscoped enumeration type, not 'char *'}}
+#pragma omp teams distribute simd dist_schedule (static, argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}} expected-error 2{{expression must have integral or unscoped enumeration type, not 'char *'}}
for (int i = 0; i < 10; ++i) foo();
return T();
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
- auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}}
+ auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}}
auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}}
template<> struct Q<&R<int>::n> { static constexpr int X = 1; };
static_assert(R<int>().f() == 1);
}
+
+namespace dependent_reference {
+ template<int &r> struct S { int *q = &r; };
+ template<int> auto f() { static int n; return S<n>(); }
+ auto v = f<0>();
+ auto w = f<1>();
+ static_assert(!is_same<decltype(v), decltype(w)>);
+ // Ensure that we can instantiate the definition of S<...>.
+ int n = *v.q + *w.q;
+}
Y<B{__func__[0]}>(); // expected-error {{reference to subobject of predefined '__func__' variable}}
}
}
+
+namespace dependent {
+ template<auto &V> struct R { static inline auto &v = V; };
+ template<auto &V, auto &W> constexpr bool operator==(R<V>, R<W>) { return &V == &W; }
+ template<auto *V> struct S { static inline auto *v = V; };
+ template<auto *V, auto *W> constexpr bool operator==(S<V>, S<W>) { return V == W; }
+ template<auto V> struct T { static inline const auto &v = V; };
+ template<auto V, auto W> constexpr bool operator==(T<V>, T<W>) { return &V == &W; }
+ template<typename T> struct V { T v; };
+ template<int N> auto f() {
+ static int n;
+ static V<int> vn;
+ if constexpr (N < 10)
+ return R<n>();
+ else if constexpr (N < 20)
+ return R<vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
+ else if constexpr (N < 30)
+ return S<&n>();
+ else if constexpr (N < 40)
+ return S<&vn.v>(); // FIXME: expected-error 2{{refers to subobject}}
+ else if constexpr (N < 50)
+ return T<V<int&>{n}>();
+ else if constexpr (N < 60)
+ return T<V<int*>{&n}>();
+ else if constexpr (N < 70)
+ return T<V<int&>{vn.v}>();
+ else if constexpr (N < 80)
+ return T<V<int*>{&vn.v}>();
+ }
+ template<int Base> void check() {
+ auto v = f<Base + 0>(); // FIXME: expected-note 2{{instantiation of}}
+ auto w = f<Base + 1>(); // FIXME: expected-note 2{{instantiation of}}
+ static_assert(!__is_same(decltype(v), decltype(w)));
+ static_assert(v != w);
+ }
+ template void check<0>();
+ template void check<10>(); // FIXME: expected-note 2{{instantiation of}}
+ template void check<20>();
+ template void check<30>(); // FIXME: expected-note 2{{instantiation of}}
+ template void check<40>();
+ template void check<50>();
+ template void check<60>();
+ template void check<70>();
+}