forked from OSchip/llvm-project
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:
parent
a8a3f73a47
commit
c7acfdfe9a
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue