]> granicus.if.org Git - clang/commitdiff
Add QualifiedDeclRefExpr, which retains additional source-location
authorDouglas Gregor <dgregor@apple.com>
Tue, 6 Jan 2009 05:10:23 +0000 (05:10 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 6 Jan 2009 05:10:23 +0000 (05:10 +0000)
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

15 files changed:
include/clang/AST/Expr.h
include/clang/AST/ExprCXX.h
include/clang/AST/StmtNodes.def
include/clang/Basic/SourceManager.h
lib/AST/Expr.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtSerialization.cpp
lib/Analysis/GRExprEngine.cpp
lib/CodeGen/CGExpr.cpp
lib/CodeGen/CGExprConstant.cpp
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp
test/SemaCXX/qualified-id-lookup.cpp

index 62a93b51e8fb1b1d9be607b21a2def5fc013bf84..0490aab2001195ce06d3782ca641355085343850 100644 (file)
@@ -273,9 +273,15 @@ class DeclRefExpr : public Expr {
   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 @@ public:
   
   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; }
   
index 37436575a2450f72fa467257671220d310b94d77..a9ff1546e957be44117c0384cab05e6248242ccd 100644 (file)
@@ -747,6 +747,33 @@ public:
   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
index 7bd378220b056685507e33377c5cc5bbb7fac7b2..26d1e89637f2749c09659416c117a03e9ee85e0f 100644 (file)
@@ -114,6 +114,7 @@ STMT(CXXNewExpr             , Expr)
 STMT(CXXDeleteExpr          , Expr)
 STMT(CXXDependentNameExpr   , Expr)
 STMT(UnaryTypeTraitExpr     , Expr)
+STMT(QualifiedDeclRefExpr   , DeclRefExpr)
 
 // Obj-C Expressions.
 STMT(ObjCStringLiteral    , Expr)
index 175c40488c6d31431355fcd66b787d8ba7fe287c..5185aa16552a9051029b2c95ee035a415ffba3c6 100644 (file)
@@ -49,6 +49,7 @@ namespace SrcMgr {
   /// 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;
index eafa717d654b2f5618b26688f35e4a9995ebac49..26260132e7ce447f83b557d5fa7ec5c18c37314e 100644 (file)
@@ -395,7 +395,8 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {
     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 @@ bool Expr::hasGlobalStorage() const {
     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 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
     return false;
   }
   case DeclRefExprClass:
+  case QualifiedDeclRefExprClass:
     if (const EnumConstantDecl *D = 
           dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) {
       Result = D->getInitVal();
index 89a185d965d566fe314cafe5907bf1c53349c3a9..679c89749752ed3174315951ae7db9e43b6f98f3 100644 (file)
@@ -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 @@ void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
   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());
index f7c4cf9b937593242410929bf2731a003c03bf0d..02ccde3da2689e2ae338a98339289ceeedcf6150 100644 (file)
@@ -249,6 +249,9 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {
 
     case CXXTryStmtClass:
       return CXXTryStmt::CreateImpl(D, C);
+
+    case QualifiedDeclRefExprClass:
+      return QualifiedDeclRefExpr::CreateImpl(D, C);
   }
 }
 
@@ -1578,3 +1581,14 @@ CXXTryStmt::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
 
   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;
+}
index b5a9cb48091689790d3ec9fcdccbfada011a32a3..1487ed6f2ca82465b204b38be1909901a7d1ee61 100644 (file)
@@ -347,6 +347,7 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) {
     }
       
     case Stmt::DeclRefExprClass:
+    case Stmt::QualifiedDeclRefExprClass:
       VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
       break;
       
@@ -446,6 +447,7 @@ void GRExprEngine::VisitLValue(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
       return;
       
     case Stmt::DeclRefExprClass:
+    case Stmt::QualifiedDeclRefExprClass:
       VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
       return;
       
index 18ccb27301f9f5de15fa879a7787d953b0b7ca2c..2742395db86df5891edebcfb17e27b8fb2043994 100644 (file)
@@ -116,7 +116,9 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) {
   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));
index a82efca6148acc3a0355d94f69e1e9d1349ede9d..71216a5d63d4fc1c51785b6d9536aaa97c3bf376 100644 (file)
@@ -542,7 +542,8 @@ public:
                                    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);
index e35c06dd2f393d5508bb38b7f6455224c7fea6dd..ccc6b8c4cbd0a14bb5f35716b3d00036a3b0547c 100644 (file)
@@ -43,6 +43,7 @@ namespace clang {
   class Expr;
   class InitListExpr;
   class CallExpr;
+  class DeclRefExpr;
   class VarDecl;
   class ParmVarDecl;
   class TypedefDecl;
@@ -674,6 +675,9 @@ public:
                                                     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,
index 14aa99682134d7677f51139e0a91e89204c8596e..5bb78cd765d8ad1074834040e2a81fd7cdbf8e04 100644 (file)
@@ -883,7 +883,8 @@ static DeclRefExpr* EvalVal(Expr *E) {
   // 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.
index 0396f520a8436b8fc989a14d9ff081b4291cc987..dce1e129a59750e1c4f4ca3d3952d2a9935f24b8 100644 (file)
@@ -1570,7 +1570,8 @@ bool Sema::CheckAddressConstantExpressionLValue(const Expr* Init) {
   }
   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 @@ bool Sema::CheckArithmeticConstantExpression(const Expr* Init) {
     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;
index 5e07dfe8d880bc1627b002f9163e3d27e6b135fb..8b2aca61ea0085aa8932cb3a9c4f51aede4421af 100644 (file)
@@ -358,6 +358,19 @@ Sema::ExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
   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 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
 
   // 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 @@ Sema::ExprResult Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
     //      (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 @@ Sema::ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc,
 
   // 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 @@ Sema::ActOnCallExpr(Scope *S, ExprTy *fn, SourceLocation LParenLoc,
       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 @@ QualType Sema::CheckIncrementDecrementOperand(Expr *Op, SourceLocation OpLoc,
 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.
index 1321d734d98fac2839821ede98e3a05b36e11172..0ef8e69107bfca028d615f63ee7992da732df2ec 100644 (file)
@@ -59,6 +59,7 @@ void test_f1(int i) {
   int &v1 = N::f1();
   float &v2 = N::f1(i);
   int v3 = ::i1;
+  int v4 = N::f1::member;
 }
 
 typedef int f2_type;