|
@@ -625,15 +625,18 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
|
|
|
Context.getTargetInfo().getCXXABI().isMicrosoft())
|
|
|
(void)isCompleteType(E->getExprLoc(), T);
|
|
|
|
|
|
- UpdateMarkingForLValueToRValue(E);
|
|
|
+ ExprResult Res = CheckLValueToRValueConversionOperand(E);
|
|
|
+ if (Res.isInvalid())
|
|
|
+ return Res;
|
|
|
+ E = Res.get();
|
|
|
|
|
|
// Loading a __weak object implicitly retains the value, so we need a cleanup to
|
|
|
// balance that.
|
|
|
if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
|
|
|
Cleanup.setExprNeedsCleanups(true);
|
|
|
|
|
|
- ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
|
|
|
- nullptr, VK_RValue);
|
|
|
+ Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E, nullptr,
|
|
|
+ VK_RValue);
|
|
|
|
|
|
// C11 6.3.2.1p2:
|
|
|
// ... if the lvalue has atomic type, the value has the non-atomic version
|
|
@@ -1794,9 +1797,19 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
|
|
|
isa<VarDecl>(D) &&
|
|
|
NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc());
|
|
|
|
|
|
+ NonOdrUseReason NOUR;
|
|
|
+ if (isUnevaluatedContext())
|
|
|
+ NOUR = NOUR_Unevaluated;
|
|
|
+ else if (isa<VarDecl>(D) && D->getType()->isReferenceType() &&
|
|
|
+ !(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) &&
|
|
|
+ cast<VarDecl>(D)->isUsableInConstantExpressions(Context))
|
|
|
+ NOUR = NOUR_Constant;
|
|
|
+ else
|
|
|
+ NOUR = NOUR_None;
|
|
|
+
|
|
|
DeclRefExpr *E = DeclRefExpr::Create(Context, NNS, TemplateKWLoc, D,
|
|
|
RefersToCapturedVariable, NameInfo, Ty,
|
|
|
- VK, FoundD, TemplateArgs);
|
|
|
+ VK, FoundD, TemplateArgs, NOUR);
|
|
|
MarkDeclRefReferenced(E);
|
|
|
|
|
|
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
|
|
@@ -5626,7 +5639,8 @@ ExprResult Sema::BuildCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc,
|
|
|
NDecl = FDecl;
|
|
|
Fn = DeclRefExpr::Create(
|
|
|
Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false,
|
|
|
- SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl);
|
|
|
+ SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl,
|
|
|
+ nullptr, DRE->isNonOdrUse());
|
|
|
}
|
|
|
}
|
|
|
} else if (isa<MemberExpr>(NakedFn))
|
|
@@ -15779,59 +15793,258 @@ QualType Sema::getCapturedDeclRefType(VarDecl *Var, SourceLocation Loc) {
|
|
|
return DeclRefType;
|
|
|
}
|
|
|
|
|
|
+/// Walk the set of potential results of an expression and mark them all as
|
|
|
+/// non-odr-uses if they satisfy the side-conditions of the NonOdrUseReason.
|
|
|
+///
|
|
|
+/// \return A new expression if we found any potential results, ExprEmpty() if
|
|
|
+/// not, and ExprError() if we diagnosed an error.
|
|
|
+static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
|
|
|
+ NonOdrUseReason NOUR) {
|
|
|
+ // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
|
|
|
+ // an object that satisfies the requirements for appearing in a
|
|
|
+ // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
|
|
|
+ // is immediately applied." This function handles the lvalue-to-rvalue
|
|
|
+ // conversion part.
|
|
|
+ //
|
|
|
+ // If we encounter a node that claims to be an odr-use but shouldn't be, we
|
|
|
+ // transform it into the relevant kind of non-odr-use node and rebuild the
|
|
|
+ // tree of nodes leading to it.
|
|
|
+ //
|
|
|
+ // This is a mini-TreeTransform that only transforms a restricted subset of
|
|
|
+ // nodes (and only certain operands of them).
|
|
|
|
|
|
+ // Rebuild a subexpression.
|
|
|
+ auto Rebuild = [&](Expr *Sub) {
|
|
|
+ return rebuildPotentialResultsAsNonOdrUsed(S, Sub, NOUR);
|
|
|
+ };
|
|
|
|
|
|
-// If either the type of the variable or the initializer is dependent,
|
|
|
-// return false. Otherwise, determine whether the variable is a constant
|
|
|
-// expression. Use this if you need to know if a variable that might or
|
|
|
-// might not be dependent is truly a constant expression.
|
|
|
-static inline bool IsVariableNonDependentAndAConstantExpression(VarDecl *Var,
|
|
|
- ASTContext &Context) {
|
|
|
+ // Check whether a potential result satisfies the requirements of NOUR.
|
|
|
+ auto IsPotentialResultOdrUsed = [&](NamedDecl *D) {
|
|
|
+ // Any entity other than a VarDecl is always odr-used whenever it's named
|
|
|
+ // in a potentially-evaluated expression.
|
|
|
+ auto *VD = dyn_cast<VarDecl>(D);
|
|
|
+ if (!VD)
|
|
|
+ return true;
|
|
|
|
|
|
- if (Var->getType()->isDependentType())
|
|
|
- return false;
|
|
|
- const VarDecl *DefVD = nullptr;
|
|
|
- Var->getAnyInitializer(DefVD);
|
|
|
- if (!DefVD)
|
|
|
- return false;
|
|
|
- EvaluatedStmt *Eval = DefVD->ensureEvaluatedStmt();
|
|
|
- Expr *Init = cast<Expr>(Eval->Value);
|
|
|
- if (Init->isValueDependent())
|
|
|
+ // C++2a [basic.def.odr]p4:
|
|
|
+ // A variable x whose name appears as a potentially-evalauted expression
|
|
|
+ // e is odr-used by e unless
|
|
|
+ // -- x is a reference that is usable in constant expressions, or
|
|
|
+ // -- x is a variable of non-reference type that is usable in constant
|
|
|
+ // expressions and has no mutable subobjects, and e is an element of
|
|
|
+ // the set of potential results of an expression of
|
|
|
+ // non-volatile-qualified non-class type to which the lvalue-to-rvalue
|
|
|
+ // conversion is applied, or
|
|
|
+ // -- x is a variable of non-reference type, and e is an element of the
|
|
|
+ // set of potential results of a discarded-value expression to which
|
|
|
+ // the lvalue-to-rvalue conversion is not applied
|
|
|
+ //
|
|
|
+ // We check the first bullet and the "potentially-evaluated" condition in
|
|
|
+ // BuildDeclRefExpr. We check the type requirements in the second bullet
|
|
|
+ // in CheckLValueToRValueConversionOperand below.
|
|
|
+ switch (NOUR) {
|
|
|
+ case NOUR_None:
|
|
|
+ case NOUR_Unevaluated:
|
|
|
+ llvm_unreachable("unexpected non-odr-use-reason");
|
|
|
+
|
|
|
+ case NOUR_Constant:
|
|
|
+ // Constant references were handled when they were built.
|
|
|
+ if (VD->getType()->isReferenceType())
|
|
|
+ return true;
|
|
|
+ if (auto *RD = VD->getType()->getAsCXXRecordDecl())
|
|
|
+ if (RD->hasMutableFields())
|
|
|
+ return true;
|
|
|
+ if (!VD->isUsableInConstantExpressions(S.Context))
|
|
|
+ return true;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NOUR_Discarded:
|
|
|
+ if (VD->getType()->isReferenceType())
|
|
|
+ return true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
return false;
|
|
|
- return IsVariableAConstantExpression(Var, Context);
|
|
|
-}
|
|
|
+ };
|
|
|
|
|
|
+ // Mark that this expression does not constitute an odr-use.
|
|
|
+ auto MarkNotOdrUsed = [&] {
|
|
|
+ S.MaybeODRUseExprs.erase(E);
|
|
|
+ if (LambdaScopeInfo *LSI = S.getCurLambda())
|
|
|
+ LSI->markVariableExprAsNonODRUsed(E);
|
|
|
+ };
|
|
|
|
|
|
-void Sema::UpdateMarkingForLValueToRValue(Expr *E) {
|
|
|
- // Per C++11 [basic.def.odr], a variable is odr-used "unless it is
|
|
|
- // an object that satisfies the requirements for appearing in a
|
|
|
- // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1)
|
|
|
- // is immediately applied." This function handles the lvalue-to-rvalue
|
|
|
- // conversion part.
|
|
|
- MaybeODRUseExprs.erase(E->IgnoreParens());
|
|
|
+ // C++2a [basic.def.odr]p2:
|
|
|
+ // The set of potential results of an expression e is defined as follows:
|
|
|
+ switch (E->getStmtClass()) {
|
|
|
+ // -- If e is an id-expression, ...
|
|
|
+ case Expr::DeclRefExprClass: {
|
|
|
+ auto *DRE = cast<DeclRefExpr>(E);
|
|
|
+ if (DRE->isNonOdrUse() || IsPotentialResultOdrUsed(DRE->getDecl()))
|
|
|
+ break;
|
|
|
|
|
|
- // If we are in a lambda, check if this DeclRefExpr or MemberExpr refers
|
|
|
- // to a variable that is a constant expression, and if so, identify it as
|
|
|
- // a reference to a variable that does not involve an odr-use of that
|
|
|
- // variable.
|
|
|
- if (LambdaScopeInfo *LSI = getCurLambda()) {
|
|
|
- Expr *SansParensExpr = E->IgnoreParens();
|
|
|
- VarDecl *Var;
|
|
|
- ArrayRef<VarDecl *> Vars(&Var, &Var + 1);
|
|
|
- if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(SansParensExpr))
|
|
|
- Var = dyn_cast<VarDecl>(DRE->getFoundDecl());
|
|
|
- else if (MemberExpr *ME = dyn_cast<MemberExpr>(SansParensExpr))
|
|
|
- Var = dyn_cast<VarDecl>(ME->getMemberDecl());
|
|
|
- else if (auto *FPPE = dyn_cast<FunctionParmPackExpr>(SansParensExpr))
|
|
|
- Vars = llvm::makeArrayRef(FPPE->begin(), FPPE->end());
|
|
|
- else
|
|
|
- Vars = None;
|
|
|
+ // Rebuild as a non-odr-use DeclRefExpr.
|
|
|
+ MarkNotOdrUsed();
|
|
|
+ TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;
|
|
|
+ if (DRE->hasExplicitTemplateArgs()) {
|
|
|
+ DRE->copyTemplateArgumentsInto(TemplateArgStorage);
|
|
|
+ TemplateArgs = &TemplateArgStorage;
|
|
|
+ }
|
|
|
+ return DeclRefExpr::Create(
|
|
|
+ S.Context, DRE->getQualifierLoc(), DRE->getTemplateKeywordLoc(),
|
|
|
+ DRE->getDecl(), DRE->refersToEnclosingVariableOrCapture(),
|
|
|
+ DRE->getNameInfo(), DRE->getType(), DRE->getValueKind(),
|
|
|
+ DRE->getFoundDecl(), TemplateArgs, NOUR);
|
|
|
+ }
|
|
|
+
|
|
|
+ case Expr::FunctionParmPackExprClass: {
|
|
|
+ auto *FPPE = cast<FunctionParmPackExpr>(E);
|
|
|
+ // If any of the declarations in the pack is odr-used, then the expression
|
|
|
+ // as a whole constitutes an odr-use.
|
|
|
+ for (VarDecl *D : *FPPE)
|
|
|
+ if (IsPotentialResultOdrUsed(D))
|
|
|
+ return ExprEmpty();
|
|
|
+
|
|
|
+ // FIXME: Rebuild as a non-odr-use FunctionParmPackExpr? In practice,
|
|
|
+ // nothing cares about whether we marked this as an odr-use, but it might
|
|
|
+ // be useful for non-compiler tools.
|
|
|
+ MarkNotOdrUsed();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // FIXME: Implement these.
|
|
|
+ // -- If e is a subscripting operation with an array operand...
|
|
|
+ // -- If e is a class member access expression [...] naming a non-static
|
|
|
+ // data member...
|
|
|
+
|
|
|
+ // -- If e is a class member access expression naming a static data member,
|
|
|
+ // ...
|
|
|
+ case Expr::MemberExprClass: {
|
|
|
+ auto *ME = cast<MemberExpr>(E);
|
|
|
+ if (ME->getMemberDecl()->isCXXInstanceMember())
|
|
|
+ // FIXME: Recurse to the left-hand side.
|
|
|
+ break;
|
|
|
+
|
|
|
+ // FIXME: Track whether a MemberExpr constitutes an odr-use; bail out here
|
|
|
+ // if we've already marked it.
|
|
|
+ if (IsPotentialResultOdrUsed(ME->getMemberDecl()))
|
|
|
+ break;
|
|
|
+
|
|
|
+ // FIXME: Rebuild as a non-odr-use MemberExpr.
|
|
|
+ MarkNotOdrUsed();
|
|
|
+ return ExprEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+ // FIXME: Implement this.
|
|
|
+ // -- If e is a pointer-to-member expression of the form e1 .* e2 ...
|
|
|
+
|
|
|
+ // -- If e has the form (e1)...
|
|
|
+ case Expr::ParenExprClass: {
|
|
|
+ auto *PE = dyn_cast<ParenExpr>(E);
|
|
|
+ ExprResult Sub = Rebuild(PE->getSubExpr());
|
|
|
+ if (!Sub.isUsable())
|
|
|
+ return Sub;
|
|
|
+ return S.ActOnParenExpr(PE->getLParen(), PE->getRParen(), Sub.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ // FIXME: Implement these.
|
|
|
+ // -- If e is a glvalue conditional expression, ...
|
|
|
+ // -- If e is a comma expression, ...
|
|
|
|
|
|
- for (VarDecl *VD : Vars) {
|
|
|
- if (VD && IsVariableNonDependentAndAConstantExpression(VD, Context))
|
|
|
- LSI->markVariableExprAsNonODRUsed(SansParensExpr);
|
|
|
+ // [Clang extension]
|
|
|
+ // -- If e has the form __extension__ e1...
|
|
|
+ case Expr::UnaryOperatorClass: {
|
|
|
+ auto *UO = cast<UnaryOperator>(E);
|
|
|
+ if (UO->getOpcode() != UO_Extension)
|
|
|
+ break;
|
|
|
+ ExprResult Sub = Rebuild(UO->getSubExpr());
|
|
|
+ if (!Sub.isUsable())
|
|
|
+ return Sub;
|
|
|
+ return S.BuildUnaryOp(nullptr, UO->getOperatorLoc(), UO_Extension,
|
|
|
+ Sub.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ // [Clang extension]
|
|
|
+ // -- If e has the form _Generic(...), the set of potential results is the
|
|
|
+ // union of the sets of potential results of the associated expressions.
|
|
|
+ case Expr::GenericSelectionExprClass: {
|
|
|
+ auto *GSE = dyn_cast<GenericSelectionExpr>(E);
|
|
|
+
|
|
|
+ SmallVector<Expr *, 4> AssocExprs;
|
|
|
+ bool AnyChanged = false;
|
|
|
+ for (Expr *OrigAssocExpr : GSE->getAssocExprs()) {
|
|
|
+ ExprResult AssocExpr = Rebuild(OrigAssocExpr);
|
|
|
+ if (AssocExpr.isInvalid())
|
|
|
+ return ExprError();
|
|
|
+ if (AssocExpr.isUsable()) {
|
|
|
+ AssocExprs.push_back(AssocExpr.get());
|
|
|
+ AnyChanged = true;
|
|
|
+ } else {
|
|
|
+ AssocExprs.push_back(OrigAssocExpr);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ return AnyChanged ? S.CreateGenericSelectionExpr(
|
|
|
+ GSE->getGenericLoc(), GSE->getDefaultLoc(),
|
|
|
+ GSE->getRParenLoc(), GSE->getControllingExpr(),
|
|
|
+ GSE->getAssocTypeSourceInfos(), AssocExprs)
|
|
|
+ : ExprEmpty();
|
|
|
+ }
|
|
|
+
|
|
|
+ // [Clang extension]
|
|
|
+ // -- If e has the form __builtin_choose_expr(...), the set of potential
|
|
|
+ // results is the union of the sets of potential results of the
|
|
|
+ // second and third subexpressions.
|
|
|
+ case Expr::ChooseExprClass: {
|
|
|
+ auto *CE = dyn_cast<ChooseExpr>(E);
|
|
|
+
|
|
|
+ ExprResult LHS = Rebuild(CE->getLHS());
|
|
|
+ if (LHS.isInvalid())
|
|
|
+ return ExprError();
|
|
|
+
|
|
|
+ ExprResult RHS = Rebuild(CE->getLHS());
|
|
|
+ if (RHS.isInvalid())
|
|
|
+ return ExprError();
|
|
|
+
|
|
|
+ if (!LHS.get() && !RHS.get())
|
|
|
+ return ExprEmpty();
|
|
|
+ if (!LHS.isUsable())
|
|
|
+ LHS = CE->getLHS();
|
|
|
+ if (!RHS.isUsable())
|
|
|
+ RHS = CE->getRHS();
|
|
|
+
|
|
|
+ return S.ActOnChooseExpr(CE->getBuiltinLoc(), CE->getCond(), LHS.get(),
|
|
|
+ RHS.get(), CE->getRParenLoc());
|
|
|
}
|
|
|
+
|
|
|
+ // Step through non-syntactic nodes.
|
|
|
+ case Expr::ConstantExprClass: {
|
|
|
+ auto *CE = dyn_cast<ConstantExpr>(E);
|
|
|
+ ExprResult Sub = Rebuild(CE->getSubExpr());
|
|
|
+ if (!Sub.isUsable())
|
|
|
+ return Sub;
|
|
|
+ return ConstantExpr::Create(S.Context, Sub.get());
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Can't traverse through this node. Nothing to do.
|
|
|
+ return ExprEmpty();
|
|
|
+}
|
|
|
+
|
|
|
+ExprResult Sema::CheckLValueToRValueConversionOperand(Expr *E) {
|
|
|
+ // C++2a [basic.def.odr]p4:
|
|
|
+ // [...] an expression of non-volatile-qualified non-class type to which
|
|
|
+ // the lvalue-to-rvalue conversion is applied [...]
|
|
|
+ if (E->getType().isVolatileQualified() || E->getType()->getAs<RecordType>())
|
|
|
+ return E;
|
|
|
+
|
|
|
+ ExprResult Result =
|
|
|
+ rebuildPotentialResultsAsNonOdrUsed(*this, E, NOUR_Constant);
|
|
|
+ if (Result.isInvalid())
|
|
|
+ return ExprError();
|
|
|
+ return Result.get() ? Result : E;
|
|
|
}
|
|
|
|
|
|
ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
|
@@ -15844,8 +16057,7 @@ ExprResult Sema::ActOnConstantExpression(ExprResult Res) {
|
|
|
// deciding whether it is an odr-use, just assume we will apply the
|
|
|
// lvalue-to-rvalue conversion. In the one case where this doesn't happen
|
|
|
// (a non-type template argument), we have special handling anyway.
|
|
|
- UpdateMarkingForLValueToRValue(Res.get());
|
|
|
- return Res;
|
|
|
+ return CheckLValueToRValueConversionOperand(Res.get());
|
|
|
}
|
|
|
|
|
|
void Sema::CleanupVarDeclMarking() {
|
|
@@ -15889,7 +16101,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|
|
|
|
|
OdrUseContext OdrUse = isOdrUseContext(SemaRef);
|
|
|
bool UsableInConstantExpr =
|
|
|
- Var->isUsableInConstantExpressions(SemaRef.Context);
|
|
|
+ Var->mightBeUsableInConstantExpressions(SemaRef.Context);
|
|
|
|
|
|
// C++20 [expr.const]p12:
|
|
|
// A variable [...] is needed for constant evaluation if it is [...] a
|
|
@@ -15964,7 +16176,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // C++20 [basic.def.odr]p4:
|
|
|
+ // C++2a [basic.def.odr]p4:
|
|
|
// A variable x whose name appears as a potentially-evaluated expression e
|
|
|
// is odr-used by e unless
|
|
|
// -- x is a reference that is usable in constant expressions
|
|
@@ -15978,11 +16190,14 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|
|
// lvalue-to-rvalue conversion is not applied [FIXME]
|
|
|
//
|
|
|
// We check the first part of the second bullet here, and
|
|
|
- // Sema::UpdateMarkingForLValueToRValue deals with the second part.
|
|
|
+ // Sema::CheckLValueToRValueConversionOperand deals with the second part.
|
|
|
// FIXME: To get the third bullet right, we need to delay this even for
|
|
|
// variables that are not usable in constant expressions.
|
|
|
+ DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E);
|
|
|
switch (OdrUse) {
|
|
|
case OdrUseContext::None:
|
|
|
+ assert((!DRE || DRE->isNonOdrUse() == NOUR_Unevaluated) &&
|
|
|
+ "missing non-odr-use marking for unevaluated operand");
|
|
|
break;
|
|
|
|
|
|
case OdrUseContext::FormallyOdrUsed:
|
|
@@ -15991,19 +16206,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|
|
break;
|
|
|
|
|
|
case OdrUseContext::Used:
|
|
|
- if (E && IsVariableAConstantExpression(Var, SemaRef.Context)) {
|
|
|
- // A reference initialized by a constant expression can never be
|
|
|
- // odr-used, so simply ignore it.
|
|
|
- if (!Var->getType()->isReferenceType() ||
|
|
|
- (SemaRef.LangOpts.OpenMP && SemaRef.isOpenMPCapturedDecl(Var)))
|
|
|
- SemaRef.MaybeODRUseExprs.insert(E);
|
|
|
- } else {
|
|
|
- MarkVarDeclODRUsed(Var, Loc, SemaRef,
|
|
|
- /*MaxFunctionScopeIndex ptr*/ nullptr);
|
|
|
- }
|
|
|
+ // If we already know this isn't an odr-use, there's nothing more to do.
|
|
|
+ if (DRE && DRE->isNonOdrUse())
|
|
|
+ break;
|
|
|
+ // If we might later find that this expression isn't actually an odr-use,
|
|
|
+ // delay the marking.
|
|
|
+ if (E && Var->isUsableInConstantExpressions(SemaRef.Context))
|
|
|
+ SemaRef.MaybeODRUseExprs.insert(E);
|
|
|
+ else
|
|
|
+ MarkVarDeclODRUsed(Var, Loc, SemaRef);
|
|
|
break;
|
|
|
|
|
|
case OdrUseContext::Dependent:
|
|
|
+ // If we already know this isn't an odr-use, there's nothing more to do.
|
|
|
+ if (DRE && DRE->isNonOdrUse())
|
|
|
+ break;
|
|
|
// If this is a dependent context, we don't need to mark variables as
|
|
|
// odr-used, but we may still need to track them for lambda capture.
|
|
|
// FIXME: Do we also need to do this inside dependent typeid expressions
|
|
@@ -16028,7 +16245,7 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
|
|
|
// FIXME: We can simplify this a lot after implementing P0588R1.
|
|
|
assert(E && "Capture variable should be used in an expression.");
|
|
|
if (!Var->getType()->isReferenceType() ||
|
|
|
- !IsVariableNonDependentAndAConstantExpression(Var, SemaRef.Context))
|
|
|
+ !Var->isUsableInConstantExpressions(SemaRef.Context))
|
|
|
LSI->addPotentialCapture(E->IgnoreParens());
|
|
|
}
|
|
|
}
|
|
@@ -16241,13 +16458,6 @@ namespace {
|
|
|
void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) {
|
|
|
Visit(E->getExpr());
|
|
|
}
|
|
|
-
|
|
|
- void VisitImplicitCastExpr(ImplicitCastExpr *E) {
|
|
|
- Inherited::VisitImplicitCastExpr(E);
|
|
|
-
|
|
|
- if (E->getCastKind() == CK_LValueToRValue)
|
|
|
- S.UpdateMarkingForLValueToRValue(E->getSubExpr());
|
|
|
- }
|
|
|
};
|
|
|
}
|
|
|
|