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.

llvm-svn: 61789
This commit is contained in:
Douglas Gregor 2009-01-06 05:10:23 +00:00
parent a8a3f73a47
commit c7acfdfe9a
15 changed files with 138 additions and 24 deletions

View 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; }

View 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

View 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)

View 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;

View 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();

View 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());

View 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;
}

View 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;

View 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));

View 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);

View 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,

View 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.

View 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;

View 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.

View 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;