summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r--lib/Sema/SemaExpr.cpp73
1 files changed, 47 insertions, 26 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5cc3fb616d..ed39278b1a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -1785,6 +1785,27 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
TemplateArgs);
}
+NonOdrUseReason Sema::getNonOdrUseReasonInCurrentContext(ValueDecl *D) {
+ // A declaration named in an unevaluated operand never constitutes an odr-use.
+ if (isUnevaluatedContext())
+ return NOUR_Unevaluated;
+
+ // 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.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (VD->getType()->isReferenceType() &&
+ !(getLangOpts().OpenMP && isOpenMPCapturedDecl(D)) &&
+ VD->isUsableInConstantExpressions(Context))
+ return NOUR_Constant;
+ }
+
+ // All remaining non-variable cases constitute an odr-use. For variables, we
+ // need to wait and see how the expression is used.
+ return NOUR_None;
+}
+
/// BuildDeclRefExpr - Build an expression that references a
/// declaration that does not require a closure capture.
DeclRefExpr *
@@ -1797,19 +1818,9 @@ 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, NOUR);
+ DeclRefExpr *E = DeclRefExpr::Create(
+ Context, NNS, TemplateKWLoc, D, RefersToCapturedVariable, NameInfo, Ty,
+ VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D));
MarkDeclRefReferenced(E);
if (getLangOpts().ObjCWeak && isa<VarDecl>(D) &&
@@ -15924,13 +15935,21 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E,
// 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()))
+ if (ME->isNonOdrUse() || IsPotentialResultOdrUsed(ME->getMemberDecl()))
break;
- // FIXME: Rebuild as a non-odr-use MemberExpr.
+ // Rebuild as a non-odr-use MemberExpr.
MarkNotOdrUsed();
+ TemplateArgumentListInfo TemplateArgStorage, *TemplateArgs = nullptr;
+ if (ME->hasExplicitTemplateArgs()) {
+ ME->copyTemplateArgumentsInto(TemplateArgStorage);
+ TemplateArgs = &TemplateArgStorage;
+ }
+ return MemberExpr::Create(
+ S.Context, ME->getBase(), ME->isArrow(), ME->getOperatorLoc(),
+ ME->getQualifierLoc(), ME->getTemplateKeywordLoc(), ME->getMemberDecl(),
+ ME->getFoundDecl(), ME->getMemberNameInfo(), TemplateArgs,
+ ME->getType(), ME->getValueKind(), ME->getObjectKind(), NOUR);
return ExprEmpty();
}
@@ -16193,11 +16212,19 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
// 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);
+
+ // If we already know this isn't an odr-use, there's nothing more to do.
+ if (DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
+ if (DRE->isNonOdrUse())
+ return;
+ if (MemberExpr *ME = dyn_cast_or_null<MemberExpr>(E))
+ if (ME->isNonOdrUse())
+ return;
+
switch (OdrUse) {
case OdrUseContext::None:
- assert((!DRE || DRE->isNonOdrUse() == NOUR_Unevaluated) &&
- "missing non-odr-use marking for unevaluated operand");
+ assert((!E || isa<FunctionParmPackExpr>(E)) &&
+ "missing non-odr-use marking for unevaluated decl ref");
break;
case OdrUseContext::FormallyOdrUsed:
@@ -16206,9 +16233,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
break;
case OdrUseContext::Used:
- // 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))
@@ -16218,9 +16242,6 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
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