]> granicus.if.org Git - clang/commitdiff
For DR712: store on a MemberExpr whether it constitutes an odr-use.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 11 Jun 2019 17:50:36 +0000 (17:50 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Tue, 11 Jun 2019 17:50:36 +0000 (17:50 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@363087 91177308-0d34-0410-b5e6-96231b3b80d8

13 files changed:
include/clang/AST/Expr.h
include/clang/AST/Stmt.h
include/clang/Sema/Sema.h
lib/AST/ASTImporter.cpp
lib/AST/Expr.cpp
lib/AST/JSONNodeDumper.cpp
lib/AST/TextNodeDumper.cpp
lib/Analysis/BodyFarm.cpp
lib/CodeGen/CGExpr.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprMember.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp

index 682e39fbf0809e2259442f79ab0f8f30cc40d6e2..92cb671651a23efed7c3ba4545fd9998628eed3a 100644 (file)
@@ -2780,7 +2780,8 @@ class MemberExpr final
 
   MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
              ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo,
-             QualType T, ExprValueKind VK, ExprObjectKind OK);
+             QualType T, ExprValueKind VK, ExprObjectKind OK,
+             NonOdrUseReason NOUR);
   MemberExpr(EmptyShell Empty)
       : Expr(MemberExprClass, Empty), Base(), MemberDecl() {}
 
@@ -2792,10 +2793,11 @@ public:
                             DeclAccessPair FoundDecl,
                             DeclarationNameInfo MemberNameInfo,
                             const TemplateArgumentListInfo *TemplateArgs,
-                            QualType T, ExprValueKind VK, ExprObjectKind OK);
+                            QualType T, ExprValueKind VK, ExprObjectKind OK,
+                            NonOdrUseReason NOUR);
 
   /// Create an implicit MemberExpr, with no location, qualifier, template
-  /// arguments, and so on.
+  /// arguments, and so on. Suitable only for non-static member access.
   static MemberExpr *CreateImplicit(const ASTContext &C, Expr *Base,
                                     bool IsArrow, ValueDecl *MemberDecl,
                                     QualType T, ExprValueKind VK,
@@ -2803,7 +2805,7 @@ public:
     return Create(C, Base, IsArrow, SourceLocation(), NestedNameSpecifierLoc(),
                   SourceLocation(), MemberDecl,
                   DeclAccessPair::make(MemberDecl, MemberDecl->getAccess()),
-                  DeclarationNameInfo(), nullptr, T, VK, OK);
+                  DeclarationNameInfo(), nullptr, T, VK, OK, NOUR_None);
   }
 
   static MemberExpr *CreateEmpty(const ASTContext &Context, bool HasQualifier,
@@ -2957,6 +2959,12 @@ public:
     return LO.AppleKext || !hasQualifier();
   }
 
+  /// Is this expression a non-odr-use reference, and if so, why?
+  /// This is only meaningful if the named member is a static member.
+  NonOdrUseReason isNonOdrUse() const {
+    return static_cast<NonOdrUseReason>(MemberExprBits.NonOdrUseReason);
+  }
+
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == MemberExprClass;
   }
index 1e8ca63952a9cbf6fbee563d4ecf78ab70166652..e89fee881911f411fd15bb1b1ecf721d03a1bae9 100644 (file)
@@ -479,6 +479,11 @@ protected:
     /// was resolved from an overloaded set having size greater than 1.
     unsigned HadMultipleCandidates : 1;
 
+    /// Value of type NonOdrUseReason indicating why this MemberExpr does
+    /// not constitute an odr-use of the named declaration. Meaningful only
+    /// when naming a static member.
+    unsigned NonOdrUseReason : 2;
+
     /// This is the location of the -> or . in the expression.
     SourceLocation OperatorLoc;
   };
index 8b9abd3a73b3ed24d23b7bd98b9a46afaac6a391..584472a06787e62982226b50574d33d414e5943c 100644 (file)
@@ -4305,6 +4305,10 @@ public:
                                         bool isAddressOfOperand,
                                 const TemplateArgumentListInfo *TemplateArgs);
 
+  /// If \p D cannot be odr-used in the current expression evaluation context,
+  /// return a reason explaining why. Otherwise, return NOUR_None.
+  NonOdrUseReason getNonOdrUseReasonInCurrentContext(ValueDecl *D);
+
   DeclRefExpr *BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
                                 SourceLocation Loc,
                                 const CXXScopeSpec *SS = nullptr);
index c4ae3b80b9635fc1a9d6e77b82a467addb50420e..14bccd77115e05ae9d92a5e90eac145fc61b70fb 100644 (file)
@@ -7113,10 +7113,11 @@ ExpectedStmt ASTNodeImporter::VisitMemberExpr(MemberExpr *E) {
     ResInfo = &ToTAInfo;
   }
 
-  return MemberExpr::Create(
-      Importer.getToContext(), ToBase, E->isArrow(), ToOperatorLoc,
-      ToQualifierLoc, ToTemplateKeywordLoc, ToMemberDecl, ToFoundDecl,
-      ToMemberNameInfo, ResInfo, ToType, E->getValueKind(), E->getObjectKind());
+  return MemberExpr::Create(Importer.getToContext(), ToBase, E->isArrow(),
+                            ToOperatorLoc, ToQualifierLoc, ToTemplateKeywordLoc,
+                            ToMemberDecl, ToFoundDecl, ToMemberNameInfo,
+                            ResInfo, ToType, E->getValueKind(),
+                            E->getObjectKind(), E->isNonOdrUse());
 }
 
 ExpectedStmt
index b772518fc70708fd1119c7409ec271a7aba3af7c..77d444151c32684a9089965b9fe93367c9384403 100644 (file)
@@ -1541,7 +1541,8 @@ UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr(
 MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
                        ValueDecl *MemberDecl,
                        const DeclarationNameInfo &NameInfo, QualType T,
-                       ExprValueKind VK, ExprObjectKind OK)
+                       ExprValueKind VK, ExprObjectKind OK,
+                       NonOdrUseReason NOUR)
     : Expr(MemberExprClass, T, VK, OK, Base->isTypeDependent(),
            Base->isValueDependent(), Base->isInstantiationDependent(),
            Base->containsUnexpandedParameterPack()),
@@ -1553,6 +1554,7 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc,
   MemberExprBits.HasQualifierOrFoundDecl = false;
   MemberExprBits.HasTemplateKWAndArgsInfo = false;
   MemberExprBits.HadMultipleCandidates = false;
+  MemberExprBits.NonOdrUseReason = NOUR;
   MemberExprBits.OperatorLoc = OperatorLoc;
 }
 
@@ -1561,7 +1563,7 @@ MemberExpr *MemberExpr::Create(
     NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc,
     ValueDecl *MemberDecl, DeclAccessPair FoundDecl,
     DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs,
-    QualType T, ExprValueKind VK, ExprObjectKind OK) {
+    QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) {
   bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl ||
                         FoundDecl.getAccess() != MemberDecl->getAccess();
   bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid();
@@ -1572,8 +1574,8 @@ MemberExpr *MemberExpr::Create(
           TemplateArgs ? TemplateArgs->size() : 0);
 
   void *Mem = C.Allocate(Size, alignof(MemberExpr));
-  MemberExpr *E = new (Mem)
-      MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, NameInfo, T, VK, OK);
+  MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl,
+                                       NameInfo, T, VK, OK, NOUR);
 
   if (HasQualOrFound) {
     // FIXME: Wrong. We should be looking at the member declaration we found.
index 1290847e1aa01c629c5c60703136bf464d23df03..2527df66f2c2bdaf1b3fbe0d3d89a0f171f8e5f3 100644 (file)
@@ -843,6 +843,12 @@ void JSONNodeDumper::VisitMemberExpr(const MemberExpr *ME) {
   JOS.attribute("name", VD && VD->getDeclName() ? VD->getNameAsString() : "");
   JOS.attribute("isArrow", ME->isArrow());
   JOS.attribute("referencedMemberDecl", createPointerRepresentation(VD));
+  switch (ME->isNonOdrUse()) {
+  case NOUR_None: break;
+  case NOUR_Unevaluated: JOS.attribute("nonOdrUseReason", "unevaluated"); break;
+  case NOUR_Constant: JOS.attribute("nonOdrUseReason", "constant"); break;
+  case NOUR_Discarded: JOS.attribute("nonOdrUseReason", "discarded"); break;
+  }
 }
 
 void JSONNodeDumper::VisitCXXNewExpr(const CXXNewExpr *NE) {
index 3b8c8f22c372abcb26513a7f23e5d7e1e8aea402..06388c28d96840a04368045463c1ad32588155d9 100644 (file)
@@ -825,6 +825,12 @@ void TextNodeDumper::VisitUnaryExprOrTypeTraitExpr(
 void TextNodeDumper::VisitMemberExpr(const MemberExpr *Node) {
   OS << " " << (Node->isArrow() ? "->" : ".") << *Node->getMemberDecl();
   dumpPointer(Node->getMemberDecl());
+  switch (Node->isNonOdrUse()) {
+  case NOUR_None: break;
+  case NOUR_Unevaluated: OS << " non_odr_use_unevaluated"; break;
+  case NOUR_Constant: OS << " non_odr_use_constant"; break;
+  case NOUR_Discarded: OS << " non_odr_use_discarded"; break;
+  }
 }
 
 void TextNodeDumper::VisitExtVectorElementExpr(
index bb70795d91a867609c8d88db4c9d2e36b36e9042..7e636ed1f588988d974e8b1a6999d988325d5e38 100644 (file)
@@ -220,7 +220,7 @@ MemberExpr *ASTMaker::makeMemberExpression(Expr *base, ValueDecl *MemberDecl,
       SourceLocation(), MemberDecl, FoundDecl,
       DeclarationNameInfo(MemberDecl->getDeclName(), SourceLocation()),
       /* TemplateArgumentListInfo=*/ nullptr, MemberDecl->getType(), ValueKind,
-      OK_Ordinary);
+      OK_Ordinary, NOUR_None);
 }
 
 ValueDecl *ASTMaker::findMemberField(const RecordDecl *RD, StringRef Name) {
index 46b1af5e1cfad52bb12132742e562ecb81898f1b..c1c9af0ddd29edd7476a54d394679a27be7de8f3 100644 (file)
@@ -1492,17 +1492,11 @@ CodeGenFunction::tryEmitAsConstant(DeclRefExpr *refExpr) {
 static DeclRefExpr *tryToConvertMemberExprToDeclRefExpr(CodeGenFunction &CGF,
                                                         const MemberExpr *ME) {
   if (auto *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) {
-    // FIXME: Copy this from the MemberExpr once we store it there.
-    NonOdrUseReason NOUR = NOUR_None;
-    if (VD->getType()->isReferenceType() &&
-        VD->isUsableInConstantExpressions(CGF.getContext()))
-      NOUR = NOUR_Constant;
-
     // Try to emit static variable member expressions as DREs.
     return DeclRefExpr::Create(
         CGF.getContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
         /*RefersToEnclosingVariableOrCapture=*/false, ME->getExprLoc(),
-        ME->getType(), ME->getValueKind(), nullptr, nullptr, NOUR);
+        ME->getType(), ME->getValueKind(), nullptr, nullptr, ME->isNonOdrUse());
   }
   return nullptr;
 }
index 5cc3fb616dfda14ec845f0fd5d608a9a6cd20ebf..ed39278b1adbd3c8c064743625b2885e3bba76cb 100644 (file)
@@ -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
index f7b46a5e0f4585593186e2c895c04375aff833f1..2431f96fb3f7547f33d7b4415190e05c7088ab1e 100644 (file)
@@ -913,9 +913,10 @@ MemberExpr *Sema::BuildMemberExpr(
     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;
index a5ed936450974c4a986b0467e92ffe6e9084e1db..4955343a42028a94bca4aca9e078e7ca39deb3e1 100644 (file)
@@ -768,6 +768,7 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) {
   E->MemberExprBits.HasQualifierOrFoundDecl = HasQualifier || HasFoundDecl;
   E->MemberExprBits.HasTemplateKWAndArgsInfo = HasTemplateInfo;
   E->MemberExprBits.HadMultipleCandidates = Record.readInt();
+  E->MemberExprBits.NonOdrUseReason = Record.readInt();
   E->MemberExprBits.OperatorLoc = Record.readSourceLocation();
 
   if (HasQualifier || HasFoundDecl) {
index 2b707520a8ee78c66a9b876c121cfe965202de04..bd715461cb9a4edb8792e2419386415a30c7a3d6 100644 (file)
@@ -686,6 +686,7 @@ void ASTStmtWriter::VisitMemberExpr(MemberExpr *E) {
   Record.AddSourceLocation(E->getMemberLoc());
   Record.push_back(E->isArrow());
   Record.push_back(E->hadMultipleCandidates());
+  Record.push_back(E->isNonOdrUse());
   Record.AddSourceLocation(E->getOperatorLoc());
 
   if (HasFoundDecl) {