Add QualifiedDeclRefExpr, which retains additional source-location
information for declarations that were referenced via a qualified-id,
e.g., N::C::value. We keep track of the location of the start of the
nested-name-specifier. Note that the difference between
QualifiedDeclRefExpr and DeclRefExpr does have an effect on the
semantics of function calls in two ways:
  1) The use of a qualified-id instead of an unqualified-id suppresses
     argument-dependent lookup
  2) If the name refers to a virtual function, the qualified-id
  version will call the function determined statically while the
  unqualified-id version will call the function determined dynamically
  (by looking up the appropriate function in the vtable).

Neither of these features is implemented yet, but we do print out
qualified names for QualifiedDeclRefExprs as part of the AST printing.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61789 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h
index 62a93b5..0490aab 100644
--- a/include/clang/AST/Expr.h
+++ b/include/clang/AST/Expr.h
@@ -273,9 +273,15 @@
   SourceLocation Loc;
 
 protected:
+  // FIXME: Eventually, this constructor will go away and all subclasses
+  // will have to provide the type- and value-dependent flags.
   DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l) :
     Expr(SC, t), D(d), Loc(l) {}
 
+  DeclRefExpr(StmtClass SC, NamedDecl *d, QualType t, SourceLocation l, bool TD,
+              bool VD) :
+    Expr(SC, t, TD, VD), D(d), Loc(l) {}
+
 public:
   // FIXME: Eventually, this constructor will go away and all clients
   // will have to provide the type- and value-dependent flags.
@@ -294,7 +300,8 @@
   
   static bool classof(const Stmt *T) { 
     return T->getStmtClass() == DeclRefExprClass ||
-           T->getStmtClass() == CXXConditionDeclExprClass; 
+           T->getStmtClass() == CXXConditionDeclExprClass ||
+           T->getStmtClass() == QualifiedDeclRefExprClass; 
   }
   static bool classof(const DeclRefExpr *) { return true; }
   
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 3743657..a9ff154 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -747,6 +747,33 @@
   static UnaryTypeTraitExpr *CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// QualifiedDeclRefExpr - A reference to a declared variable,
+/// function, enum, etc., that includes a qualification, e.g.,
+/// "N::foo".
+class QualifiedDeclRefExpr : public DeclRefExpr {
+  /// NestedNameLoc - The location of the beginning of the
+  /// nested-name-specifier that qualifies this declaration.
+  SourceLocation NestedNameLoc;
+
+public:
+  QualifiedDeclRefExpr(NamedDecl *d, QualType t, SourceLocation l, bool TD, 
+                       bool VD, SourceLocation nnl)
+    : DeclRefExpr(QualifiedDeclRefExprClass, d, t, l, TD, VD), 
+      NestedNameLoc(nnl) { }
+
+  virtual SourceRange getSourceRange() const { 
+    return SourceRange(NestedNameLoc, getLocation()); 
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == QualifiedDeclRefExprClass;
+  }
+  static bool classof(const QualifiedDeclRefExpr *) { return true; }
+
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static QualifiedDeclRefExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 }  // end namespace clang
 
 #endif
diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def
index 7bd3782..26d1e89 100644
--- a/include/clang/AST/StmtNodes.def
+++ b/include/clang/AST/StmtNodes.def
@@ -114,6 +114,7 @@
 STMT(CXXDeleteExpr          , Expr)
 STMT(CXXDependentNameExpr   , Expr)
 STMT(UnaryTypeTraitExpr     , Expr)
+STMT(QualifiedDeclRefExpr   , DeclRefExpr)
 
 // Obj-C Expressions.
 STMT(ObjCStringLiteral    , Expr)
diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h
index 175c404..5185aa1 100644
--- a/include/clang/Basic/SourceManager.h
+++ b/include/clang/Basic/SourceManager.h
@@ -49,6 +49,7 @@
   /// ContentCache - Once instance of this struct is kept for every file
   ///  loaded or used.  This object owns the MemoryBuffer object.
   class ContentCache {
+  public: 
     /// Buffer - The actual buffer containing the characters from the input
     /// file.  This is owned by the ContentCache object.
     const llvm::MemoryBuffer* Buffer;
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index eafa717..2626013 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -395,7 +395,8 @@
     if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType())
       return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx);
     return LV_Valid;
-  case DeclRefExprClass: { // C99 6.5.1p2
+  case DeclRefExprClass: 
+  case QualifiedDeclRefExprClass: { // C99 6.5.1p2
     const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl();
     if (DeclCanBeLvalue(RefdDecl, Ctx))
       return LV_Valid;
@@ -638,7 +639,8 @@
     return cast<ImplicitCastExpr>(this)->getSubExpr()->hasGlobalStorage();
   case CompoundLiteralExprClass:
     return cast<CompoundLiteralExpr>(this)->isFileScope();
-  case DeclRefExprClass: {
+  case DeclRefExprClass:
+  case QualifiedDeclRefExprClass: {
     const Decl *D = cast<DeclRefExpr>(this)->getDecl();
     if (const VarDecl *VD = dyn_cast<VarDecl>(D))
       return VD->hasGlobalStorage();
@@ -813,6 +815,7 @@
     return false;
   }
   case DeclRefExprClass:
+  case QualifiedDeclRefExprClass:
     if (const EnumConstantDecl *D = 
           dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) {
       Result = D->getInitVal();
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 89a185d..679c897 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/AST/StmtVisitor.h"
+#include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "llvm/Support/Compiler.h"
@@ -513,6 +514,35 @@
   OS << Node->getDecl()->getNameAsString();
 }
 
+void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) {
+  // FIXME: Should we keep enough information in QualifiedDeclRefExpr
+  // to produce the same qualification that the user wrote?
+  llvm::SmallVector<DeclContext *, 4> Contexts;
+  
+  NamedDecl *D = Node->getDecl();
+
+  // Build up a stack of contexts.
+  DeclContext *Ctx = 0;
+  if (ScopedDecl *SD = dyn_cast<ScopedDecl>(D))
+    Ctx = SD->getDeclContext();
+  else if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
+    Ctx = Ovl->getDeclContext();
+  for (; Ctx; Ctx = Ctx->getParent())
+    if (!Ctx->isTransparentContext())
+      Contexts.push_back(Ctx);
+
+  while (!Contexts.empty()) {
+    DeclContext *Ctx = Contexts.back();
+    if (isa<TranslationUnitDecl>(Ctx))
+      OS << "::";
+    else if (ScopedDecl *SD = dyn_cast<ScopedDecl>(Ctx))
+      OS << SD->getNameAsString() << "::";
+    Contexts.pop_back();
+  }
+
+  OS << D->getNameAsString();
+}
+
 void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) {
   if (Node->getBase()) {
     PrintExpr(Node->getBase());
diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp
index f7c4cf9..02ccde3 100644
--- a/lib/AST/StmtSerialization.cpp
+++ b/lib/AST/StmtSerialization.cpp
@@ -249,6 +249,9 @@
 
     case CXXTryStmtClass:
       return CXXTryStmt::CreateImpl(D, C);
+
+    case QualifiedDeclRefExprClass:
+      return QualifiedDeclRefExpr::CreateImpl(D, C);
   }
 }
 
@@ -1578,3 +1581,14 @@
 
   return new CXXTryStmt(TryLoc, Stmts[0], &Stmts[1], size - 1);
 }
+
+void QualifiedDeclRefExpr::EmitImpl(llvm::Serializer& S) const {
+  DeclRefExpr::EmitImpl(S);
+  S.Emit(NestedNameLoc);
+}
+
+QualifiedDeclRefExpr* 
+QualifiedDeclRefExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
+  assert(false && "Cannot deserialize qualified decl references");
+  return 0;
+}
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index b5a9cb4..1487ed6 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -347,6 +347,7 @@
     }
       
     case Stmt::DeclRefExprClass:
+    case Stmt::QualifiedDeclRefExprClass:
       VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
       break;
       
@@ -446,6 +447,7 @@
       return;
       
     case Stmt::DeclRefExprClass:
+    case Stmt::QualifiedDeclRefExprClass:
       VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
       return;
       
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 18ccb27..2742395 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -116,7 +116,9 @@
   case Expr::CallExprClass: 
   case Expr::CXXOperatorCallExprClass:
     return EmitCallExprLValue(cast<CallExpr>(E));
-  case Expr::DeclRefExprClass: return EmitDeclRefLValue(cast<DeclRefExpr>(E));
+  case Expr::DeclRefExprClass: 
+  case Expr::QualifiedDeclRefExprClass:
+    return EmitDeclRefLValue(cast<DeclRefExpr>(E));
   case Expr::ParenExprClass:return EmitLValue(cast<ParenExpr>(E)->getSubExpr());
   case Expr::PredefinedExprClass:
     return EmitPredefinedLValue(cast<PredefinedExpr>(E));
diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp
index a82efca..71216a5 100644
--- a/lib/CodeGen/CGExprConstant.cpp
+++ b/lib/CodeGen/CGExprConstant.cpp
@@ -542,7 +542,8 @@
                                    C, ".compoundliteral", &CGM.getModule());
       return C;
     }
-    case Expr::DeclRefExprClass: {
+    case Expr::DeclRefExprClass: 
+    case Expr::QualifiedDeclRefExprClass: {
       NamedDecl *Decl = cast<DeclRefExpr>(E)->getDecl();
       if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(Decl))
         return CGM.GetAddrOfFunction(FD);
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index e35c06d..ccc6b8c 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -43,6 +43,7 @@
   class Expr;
   class InitListExpr;
   class CallExpr;
+  class DeclRefExpr;
   class VarDecl;
   class ParmVarDecl;
   class TypedefDecl;
@@ -674,6 +675,9 @@
                                                     TypeTy *Ty,
                                                     bool HasTrailingLParen,
                                                     const CXXScopeSpec &SS);
+  DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
+                                bool TypeDependent, bool ValueDependent,
+                                const CXXScopeSpec *SS = 0);
   ExprResult ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
                                       DeclarationName Name,
                                       bool HasTrailingLParen,
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 14aa996..5bb78cd 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -883,7 +883,8 @@
   // viewed AST node.  We then recursively traverse the AST by calling
   // EvalAddr and EvalVal appropriately.
   switch (E->getStmtClass()) {
-  case Stmt::DeclRefExprClass: {
+  case Stmt::DeclRefExprClass: 
+  case Stmt::QualifiedDeclRefExprClass: {
     // DeclRefExpr: the base case.  When we hit a DeclRefExpr we are looking
     //  at code that refers to a variable's name.  We check if it has local
     //  storage within the function, and if so, return the expression.
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 0396f52..dce1e12 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1570,7 +1570,8 @@
   }
   case Expr::CompoundLiteralExprClass:
     return cast<CompoundLiteralExpr>(Init)->isFileScope();
-  case Expr::DeclRefExprClass: {
+  case Expr::DeclRefExprClass: 
+  case Expr::QualifiedDeclRefExprClass: {
     const Decl *D = cast<DeclRefExpr>(Init)->getDecl();
     if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
       if (VD->hasGlobalStorage())
@@ -1829,7 +1830,8 @@
     InitializerElementNotConstant(Init);
     return true;
   }
-  case Expr::DeclRefExprClass: {
+  case Expr::DeclRefExprClass:
+  case Expr::QualifiedDeclRefExprClass: {
     const Decl *D = cast<DeclRefExpr>(Init)->getDecl();
     if (isa<EnumConstantDecl>(D))
       return false;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5e07dfe..8b2aca6 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -358,6 +358,19 @@
   return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS);
 }
 
+/// BuildDeclRefExpr - Build either a DeclRefExpr or a
+/// QualifiedDeclRefExpr based on whether or not SS is a
+/// nested-name-specifier.
+DeclRefExpr *Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
+                                    bool TypeDependent, bool ValueDependent,
+                                    const CXXScopeSpec *SS) {
+  if (SS && !SS->isEmpty())
+    return new QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent,
+                                    SS->getRange().getBegin());
+  else
+    return new DeclRefExpr(D, Ty, Loc, TypeDependent, ValueDependent);
+}
+
 /// ActOnDeclarationNameExpr - The parser has read some kind of name
 /// (e.g., a C++ id-expression (C++ [expr.prim]p1)). This routine
 /// performs lookup on that name and returns an expression that refers
@@ -536,7 +549,7 @@
 
   // Make the DeclRefExpr or BlockDeclRefExpr for the decl.
   if (OverloadedFunctionDecl *Ovl = dyn_cast<OverloadedFunctionDecl>(D))
-    return new DeclRefExpr(Ovl, Context.OverloadTy, Loc);
+    return BuildDeclRefExpr(Ovl, Context.OverloadTy, Loc, false, false, SS);
 
   ValueDecl *VD = cast<ValueDecl>(D);
   
@@ -634,8 +647,8 @@
     //      (FIXME!).
   }
 
-  return new DeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
-                         TypeDependent, ValueDependent);
+  return BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(), Loc,
+                          TypeDependent, ValueDependent, SS);
 }
 
 Sema::ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc,
@@ -1595,17 +1608,15 @@
 
   // If we're directly calling a function or a set of overloaded
   // functions, get the appropriate declaration.
-  {
-    DeclRefExpr *DRExpr = NULL;
-    if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
-      DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr());
-    else 
-      DRExpr = dyn_cast<DeclRefExpr>(Fn);
-
-    if (DRExpr) {
-      FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
-      Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
-    }
+  DeclRefExpr *DRExpr = NULL;
+  if (ImplicitCastExpr *IcExpr = dyn_cast<ImplicitCastExpr>(Fn))
+    DRExpr = dyn_cast<DeclRefExpr>(IcExpr->getSubExpr());
+  else 
+    DRExpr = dyn_cast<DeclRefExpr>(Fn);
+  
+  if (DRExpr) {
+    FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
+    Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
   }
 
   if (Ovl) {
@@ -1615,8 +1626,14 @@
       return true;
 
     // Update Fn to refer to the actual function selected.
-    Expr *NewFn = new DeclRefExpr(FDecl, FDecl->getType(), 
-                                  Fn->getSourceRange().getBegin());
+    Expr *NewFn = 0;
+    if (QualifiedDeclRefExpr *QDRExpr = dyn_cast<QualifiedDeclRefExpr>(DRExpr))
+      NewFn = new QualifiedDeclRefExpr(FDecl, FDecl->getType(), 
+                                       QDRExpr->getLocation(), false, false,
+                                       QDRExpr->getSourceRange().getBegin());
+    else
+      NewFn = new DeclRefExpr(FDecl, FDecl->getType(), 
+                              Fn->getSourceRange().getBegin());
     Fn->Destroy(Context);
     Fn = NewFn;
   }
@@ -2928,6 +2945,7 @@
 static NamedDecl *getPrimaryDecl(Expr *E) {
   switch (E->getStmtClass()) {
   case Stmt::DeclRefExprClass:
+  case Stmt::QualifiedDeclRefExprClass:
     return cast<DeclRefExpr>(E)->getDecl();
   case Stmt::MemberExprClass:
     // Fields cannot be declared with a 'register' storage class.
diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp
index 1321d73..0ef8e69 100644
--- a/test/SemaCXX/qualified-id-lookup.cpp
+++ b/test/SemaCXX/qualified-id-lookup.cpp
@@ -59,6 +59,7 @@
   int &v1 = N::f1();
   float &v2 = N::f1(i);
   int v3 = ::i1;
+  int v4 = N::f1::member;
 }
 
 typedef int f2_type;