For DR712: store on a MemberExpr whether it constitutes an odr-use.

llvm-svn: 363087
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5cc3fb6..ed39278 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -1785,6 +1785,27 @@
                           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 @@
       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 @@
       // 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 @@
   // 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 @@
     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 @@
     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
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index f7b46a5..2431f96 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -913,9 +913,10 @@
     QualType Ty, ExprValueKind VK, ExprObjectKind OK,
     const TemplateArgumentListInfo *TemplateArgs) {
   assert((!IsArrow || Base->isRValue()) && "-> base must be a pointer rvalue");
-  MemberExpr *E = MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS,
-                                     TemplateKWLoc, Member, FoundDecl,
-                                     MemberNameInfo, TemplateArgs, Ty, VK, OK);
+  MemberExpr *E =
+      MemberExpr::Create(Context, Base, IsArrow, OpLoc, NNS, TemplateKWLoc,
+                         Member, FoundDecl, MemberNameInfo, TemplateArgs, Ty,
+                         VK, OK, getNonOdrUseReasonInCurrentContext(Member));
   E->setHadMultipleCandidates(HadMultipleCandidates);
   MarkMemberReferenced(E);
   return E;