diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-01-06 05:10:23 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-01-06 05:10:23 +0000 |
commit | 1a49af9681c350fef58e677f85ccb9a77e8e9d0a (patch) | |
tree | 77fdf978b985604b42294f186108d5cd2ddad66c | |
parent | b31757b68afe06ba442a05775d08fe7aa0f6f889 (diff) |
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
-rw-r--r-- | include/clang/AST/Expr.h | 9 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 27 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 1 | ||||
-rw-r--r-- | include/clang/Basic/SourceManager.h | 1 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 7 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 30 | ||||
-rw-r--r-- | lib/AST/StmtSerialization.cpp | 14 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 2 | ||||
-rw-r--r-- | lib/CodeGen/CGExpr.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaChecking.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 50 | ||||
-rw-r--r-- | test/SemaCXX/qualified-id-lookup.cpp | 1 |
15 files changed, 138 insertions, 24 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 62a93b51e8..0490aab200 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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; } diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 37436575a2..a9ff1546e9 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -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 diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index 7bd378220b..26d1e89637 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -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) diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 175c40488c..5185aa1655 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -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; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index eafa717d65..26260132e7 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -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(); diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 89a185d965..679c897497 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 @@ 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()); diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index f7c4cf9b93..02ccde3da2 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -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; +} diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index b5a9cb4809..1487ed6f2c 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -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; diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 18ccb27301..2742395db8 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -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)); diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index a82efca614..71216a5d63 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -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); diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e35c06dd2f..ccc6b8c4cb 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 14aa996821..5bb78cd765 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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. diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0396f520a8..dce1e129a5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5e07dfe8d8..8b2aca61ea 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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. diff --git a/test/SemaCXX/qualified-id-lookup.cpp b/test/SemaCXX/qualified-id-lookup.cpp index 1321d734d9..0ef8e69107 100644 --- a/test/SemaCXX/qualified-id-lookup.cpp +++ b/test/SemaCXX/qualified-id-lookup.cpp @@ -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; |