]> granicus.if.org Git - clang/commitdiff
Add an optional field attached to a DeclRefExpr which points back to the
authorChandler Carruth <chandlerc@gmail.com>
Sun, 1 May 2011 23:48:14 +0000 (23:48 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Sun, 1 May 2011 23:48:14 +0000 (23:48 +0000)
Decl actually found via name lookup & overload resolution when that Decl
is different from the ValueDecl which is actually referenced by the
expression.

This can be used by AST consumers to correctly attribute references to
the spelling location of a using declaration, and otherwise gain insight
into the name resolution performed by Clang.

The public interface to DRE is kept as narrow as possible: we provide
a getFoundDecl() which always returns a NamedDecl, either the ValueDecl
referenced or the new, more precise NamedDecl if present. This way AST
clients can code against getFoundDecl without know when exactly the AST
has a split representation.

For an example of the data this provides consider:
% cat x.cc
namespace N1 {
  struct S {};
  void f(const S&);
}
void test(N1::S s) {
  f(s);
  using N1::f;
  f(s);
}

% ./bin/clang -fsyntax-only -Xclang -ast-dump x.cc
[...]
void test(N1::S s) (CompoundStmt 0x5b02010 <x.cc:5:20, line:9:1>
  (CallExpr 0x5b01df0 <line:6:3, col:6> 'void'
    (ImplicitCastExpr 0x5b01dd8 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
      (DeclRefExpr 0x5b01d80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)'))
    (ImplicitCastExpr 0x5b01e20 <col:5> 'const struct N1::S' lvalue <NoOp>
      (DeclRefExpr 0x5b01d58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S')))
  (DeclStmt 0x5b01ee0 <line:7:3, col:14>
    0x5b01e40 "UsingN1::;")
  (CallExpr 0x5b01fc8 <line:8:3, col:6> 'void'
    (ImplicitCastExpr 0x5b01fb0 <col:3> 'void (*)(const struct N1::S &)' <FunctionToPointerDecay>
      (DeclRefExpr 0x5b01f80 <col:3> 'void (const struct N1::S &)' lvalue Function 0x5b01a20 'f' 'void (const struct N1::S &)' (UsingShadow 0x5b01ea0 'f')))
    (ImplicitCastExpr 0x5b01ff8 <col:5> 'const struct N1::S' lvalue <NoOp>
      (DeclRefExpr 0x5b01f58 <col:5> 'N1::S':'struct N1::S' lvalue ParmVar 0x5b01b60 's' 'N1::S':'struct N1::S'))))

Now we can tell that the second call is 'using' (no pun intended) the using
declaration, and *which* using declaration it sees. Without this, we can
mistake calls that go through using declarations for ADL calls, and have no way
to attribute names looked up with using declarations to the appropriate
UsingDecl.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@130670 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
include/clang/AST/Stmt.h
lib/AST/ASTImporter.cpp
lib/AST/Expr.cpp
lib/AST/StmtDumper.cpp
lib/Sema/SemaOverload.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp

index 980ad376fb114d6241314720c4bcc5cab716f7d1..363dca75b4a12320a0a6b59ed66341b79a088d56 100644 (file)
@@ -675,6 +675,10 @@ struct ExplicitTemplateArgumentList {
 ///   DeclRefExprBits.HasQualifier:
 ///       Specifies when this declaration reference expression has a C++
 ///       nested-name-specifier.
+///   DeclRefExprBits.HasFoundDecl:
+///       Specifies when this declaration reference expression has a record of
+///       a NamedDecl (different from the referenced ValueDecl) which was found
+///       during name lookup and/or overload resolution.
 ///   DeclRefExprBits.HasExplicitTemplateArgs:
 ///       Specifies when this declaration reference expression has an explicit
 ///       C++ template argument list.
@@ -700,13 +704,34 @@ class DeclRefExpr : public Expr {
     return const_cast<DeclRefExpr *>(this)->getInternalQualifierLoc();
   }
 
+  /// \brief Test whether there is a distinct FoundDecl attached to the end of
+  /// this DRE.
+  bool hasFoundDecl() const { return DeclRefExprBits.HasFoundDecl; }
+
+  /// \brief Helper to retrieve the optional NamedDecl through which this
+  /// reference occured.
+  NamedDecl *&getInternalFoundDecl() {
+    assert(hasFoundDecl());
+    if (hasQualifier())
+      return *reinterpret_cast<NamedDecl **>(&getInternalQualifierLoc() + 1);
+    return *reinterpret_cast<NamedDecl **>(this + 1);
+  }
+
+  /// \brief Helper to retrieve the optional NamedDecl through which this
+  /// reference occured.
+  NamedDecl *getInternalFoundDecl() const {
+    return const_cast<DeclRefExpr *>(this)->getInternalFoundDecl();
+  }
+
   DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
               ValueDecl *D, SourceLocation NameLoc,
+              NamedDecl *FoundD,
               const TemplateArgumentListInfo *TemplateArgs,
               QualType T, ExprValueKind VK);
 
   DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
               ValueDecl *D, const DeclarationNameInfo &NameInfo,
+              NamedDecl *FoundD,
               const TemplateArgumentListInfo *TemplateArgs,
               QualType T, ExprValueKind VK);
 
@@ -724,6 +749,7 @@ public:
       D(D), Loc(L) {
     DeclRefExprBits.HasQualifier = 0;
     DeclRefExprBits.HasExplicitTemplateArgs = 0;
+    DeclRefExprBits.HasFoundDecl = 0;
     computeDependence();
   }
 
@@ -732,6 +758,7 @@ public:
                              ValueDecl *D,
                              SourceLocation NameLoc,
                              QualType T, ExprValueKind VK,
+                             NamedDecl *FoundD = 0,
                              const TemplateArgumentListInfo *TemplateArgs = 0);
 
   static DeclRefExpr *Create(ASTContext &Context,
@@ -739,11 +766,13 @@ public:
                              ValueDecl *D,
                              const DeclarationNameInfo &NameInfo,
                              QualType T, ExprValueKind VK,
+                             NamedDecl *FoundD = 0,
                              const TemplateArgumentListInfo *TemplateArgs = 0);
 
   /// \brief Construct an empty declaration reference expression.
   static DeclRefExpr *CreateEmpty(ASTContext &Context,
-                                  bool HasQualifier, 
+                                  bool HasQualifier,
+                                  bool HasFoundDecl,
                                   bool HasExplicitTemplateArgs,
                                   unsigned NumTemplateArgs);
 
@@ -781,6 +810,21 @@ public:
     return getInternalQualifierLoc();
   }
 
+  /// \brief Get the NamedDecl through which this reference occured.
+  ///
+  /// This Decl may be different from the ValueDecl actually referred to in the
+  /// presence of using declarations, etc. It always returns non-NULL, and may
+  /// simple return the ValueDecl when appropriate.
+  NamedDecl *getFoundDecl() {
+    return hasFoundDecl() ? getInternalFoundDecl() : D;
+  }
+
+  /// \brief Get the NamedDecl through which this reference occurred.
+  /// See non-const variant.
+  const NamedDecl *getFoundDecl() const {
+    return hasFoundDecl() ? getInternalFoundDecl() : D;
+  }
+
   /// \brief Determines whether this declaration reference was followed by an
   /// explict template argument list.
   bool hasExplicitTemplateArgs() const {
@@ -791,11 +835,15 @@ public:
   /// member template name.
   ExplicitTemplateArgumentList &getExplicitTemplateArgs() {
     assert(hasExplicitTemplateArgs());
-    if (!hasQualifier())
-      return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
+    if (hasFoundDecl())
+      return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+        &getInternalFoundDecl() + 1);
 
-    return *reinterpret_cast<ExplicitTemplateArgumentList *>(
-      &getInternalQualifierLoc() + 1);
+    if (hasQualifier())
+      return *reinterpret_cast<ExplicitTemplateArgumentList *>(
+        &getInternalQualifierLoc() + 1);
+
+    return *reinterpret_cast<ExplicitTemplateArgumentList *>(this + 1);
   }
 
   /// \brief Retrieve the explicit template argument list that followed the
index 903096e137cd8cf9b0ff79fb8fffc7afd88f0c50..695fb0403eadd83a2acdab6eb5b96e058c2aafb9 100644 (file)
@@ -165,6 +165,7 @@ protected:
 
     unsigned HasQualifier : 1;
     unsigned HasExplicitTemplateArgs : 1;
+    unsigned HasFoundDecl : 1;
   };
 
   class CastExprBitfields {
index 3907b1a31912951047d874b631f477bc8af55bee..b14560e298ef5ac13049fb56853459bfea1882ea 100644 (file)
@@ -3765,6 +3765,13 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
   ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl()));
   if (!ToD)
     return 0;
+
+  NamedDecl *FoundD = 0;
+  if (E->getDecl() != E->getFoundDecl()) {
+    FoundD = cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl()));
+    if (!FoundD)
+      return 0;
+  }
   
   QualType T = Importer.Import(E->getType());
   if (T.isNull())
@@ -3775,6 +3782,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) {
                              ToD,
                              Importer.Import(E->getLocation()),
                              T, E->getValueKind(),
+                             FoundD,
                              /*FIXME:TemplateArgs=*/0);
 }
 
index 92e66722ef8798d5c29a94cc2e9ea85877b67c16..bba35ef532ff466e40b31e1de5c52cc33a792c7c 100644 (file)
@@ -274,8 +274,9 @@ void DeclRefExpr::computeDependence() {
     ExprBits.ContainsUnexpandedParameterPack = true;
 }
 
-DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc, 
+DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
                          ValueDecl *D, SourceLocation NameLoc,
+                         NamedDecl *FoundD,
                          const TemplateArgumentListInfo *TemplateArgs,
                          QualType T, ExprValueKind VK)
   : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
@@ -283,17 +284,19 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
   DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
   if (QualifierLoc)
     getInternalQualifierLoc() =  QualifierLoc;
-
+  DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
+  if (FoundD)
+    getInternalFoundDecl() = FoundD;
   DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0;
-  if (TemplateArgs) {
+  if (TemplateArgs)
     getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
-  }
 
   computeDependence();
 }
 
 DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
                          ValueDecl *D, const DeclarationNameInfo &NameInfo,
+                         NamedDecl *FoundD,
                          const TemplateArgumentListInfo *TemplateArgs,
                          QualType T, ExprValueKind VK)
   : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false),
@@ -301,7 +304,9 @@ DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc,
   DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0;
   if (QualifierLoc)
     getInternalQualifierLoc() = QualifierLoc;
-
+  DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0;
+  if (FoundD)
+    getInternalFoundDecl() = FoundD;
   DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0;
   if (TemplateArgs)
     getExplicitTemplateArgs().initializeFrom(*TemplateArgs);
@@ -315,10 +320,11 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
                                  SourceLocation NameLoc,
                                  QualType T,
                                  ExprValueKind VK,
+                                 NamedDecl *FoundD,
                                  const TemplateArgumentListInfo *TemplateArgs) {
   return Create(Context, QualifierLoc, D,
                 DeclarationNameInfo(D->getDeclName(), NameLoc),
-                T, VK, TemplateArgs);
+                T, VK, FoundD, TemplateArgs);
 }
 
 DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
@@ -327,29 +333,38 @@ DeclRefExpr *DeclRefExpr::Create(ASTContext &Context,
                                  const DeclarationNameInfo &NameInfo,
                                  QualType T,
                                  ExprValueKind VK,
+                                 NamedDecl *FoundD,
                                  const TemplateArgumentListInfo *TemplateArgs) {
+  // Filter out cases where the found Decl is the same as the value refenenced.
+  if (D == FoundD)
+    FoundD = 0;
+
   std::size_t Size = sizeof(DeclRefExpr);
   if (QualifierLoc != 0)
     Size += sizeof(NestedNameSpecifierLoc);
-  
+  if (FoundD)
+    Size += sizeof(NamedDecl *);
   if (TemplateArgs)
     Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs);
-  
+
   void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
-  return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, TemplateArgs, T, VK);
+  return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs,
+                               T, VK);
 }
 
-DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, 
+DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context,
                                       bool HasQualifier,
+                                      bool HasFoundDecl,
                                       bool HasExplicitTemplateArgs,
                                       unsigned NumTemplateArgs) {
   std::size_t Size = sizeof(DeclRefExpr);
   if (HasQualifier)
     Size += sizeof(NestedNameSpecifierLoc);
-  
+  if (HasFoundDecl)
+    Size += sizeof(NamedDecl *);
   if (HasExplicitTemplateArgs)
     Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs);
-  
+
   void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>());
   return new (Mem) DeclRefExpr(EmptyShell());
 }
index f74556931dfd7270d1df6cb1844095e9bcf624fa..fb024f33ab3045bd4f7d057de9ed63251887e714 100644 (file)
@@ -369,6 +369,11 @@ void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) {
 
   OS << " ";
   DumpDeclRef(Node->getDecl());
+  if (Node->getDecl() != Node->getFoundDecl()) {
+    OS << " (";
+    DumpDeclRef(Node->getFoundDecl());
+    OS << ")";
+  }
 }
 
 void StmtDumper::DumpDeclRef(Decl *d) {
index 6c529208e40467e56d486d520d1a068ba20460e2..3f3ed0e1f90244113561b81b88d2defd45b8efb7 100644 (file)
@@ -9244,6 +9244,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
                                ULE->getNameLoc(),
                                Fn->getType(),
                                VK_LValue,
+                               Found.getDecl(),
                                TemplateArgs);
   }
 
@@ -9267,6 +9268,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
                                    MemExpr->getMemberLoc(),
                                    Fn->getType(),
                                    VK_LValue,
+                                   Found.getDecl(),
                                    TemplateArgs);
       } else {
         SourceLocation Loc = MemExpr->getMemberLoc();
index 6b49b7ba6c2513153a5fe077d13f65f332f68f43..918db7e367c675e3945463ca50455829b8f2e2fc 100644 (file)
@@ -426,6 +426,7 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
   VisitExpr(E);
 
   E->DeclRefExprBits.HasQualifier = Record[Idx++];
+  E->DeclRefExprBits.HasFoundDecl = Record[Idx++];
   E->DeclRefExprBits.HasExplicitTemplateArgs = Record[Idx++];
   unsigned NumTemplateArgs = 0;
   if (E->hasExplicitTemplateArgs())
@@ -435,6 +436,9 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) {
     E->getInternalQualifierLoc()
       = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
 
+  if (E->hasFoundDecl())
+    E->getInternalFoundDecl() = cast<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+
   if (E->hasExplicitTemplateArgs())
     ReadExplicitTemplateArgumentList(E->getExplicitTemplateArgs(),
                                      NumTemplateArgs);
@@ -1566,12 +1570,13 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       break;
 
     case EXPR_DECL_REF:
-      S = DeclRefExpr::CreateEmpty(*Context,
-                         /*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
-          /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1],
-                  /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 1]
-                                   ? Record[ASTStmtReader::NumExprFields + 2] 
-                                   : 0);
+      S = DeclRefExpr::CreateEmpty(
+        *Context,
+        /*HasQualifier=*/Record[ASTStmtReader::NumExprFields],
+        /*HasFoundDecl=*/Record[ASTStmtReader::NumExprFields + 1],
+        /*HasExplicitTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2],
+        /*NumTemplateArgs=*/Record[ASTStmtReader::NumExprFields + 2] ?
+          Record[ASTStmtReader::NumExprFields + 3] : 0);
       break;
 
     case EXPR_INTEGER_LITERAL:
index 4fe3bae91a27aae3d01f5eb6ca1348ac0ca695a7..bd5889ad9299a88fd119ecc18e4275ebbd42d9a2 100644 (file)
@@ -384,6 +384,7 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
   VisitExpr(E);
 
   Record.push_back(E->hasQualifier());
+  Record.push_back(E->getDecl() != E->getFoundDecl());
   Record.push_back(E->hasExplicitTemplateArgs());
 
   if (E->hasExplicitTemplateArgs()) {
@@ -394,6 +395,9 @@ void ASTStmtWriter::VisitDeclRefExpr(DeclRefExpr *E) {
   if (E->hasQualifier())
     Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
 
+  if (E->getDecl() != E->getFoundDecl())
+    Writer.AddDeclRef(E->getFoundDecl(), Record);
+
   if (E->hasExplicitTemplateArgs())
     AddExplicitTemplateArgumentList(E->getExplicitTemplateArgs());