Push nested-name-specifier source-location information into

pseudo-destructor expressions. Also, clean up some
template-instantiation and type-checking issues with
pseudo-destructors.

llvm-svn: 126498
This commit is contained in:
Douglas Gregor 2011-02-25 18:19:59 +00:00
parent 40c5e1ada7
commit a6ce608b97
10 changed files with 139 additions and 77 deletions

View File

@ -1331,13 +1331,9 @@ class CXXPseudoDestructorExpr : public Expr {
/// \brief The location of the '.' or '->' operator.
SourceLocation OperatorLoc;
/// \brief The nested-name-specifier that follows the operator, if present.
NestedNameSpecifier *Qualifier;
/// \brief The source range that covers the nested-name-specifier, if
/// present.
SourceRange QualifierRange;
NestedNameSpecifierLoc QualifierLoc;
/// \brief The type that precedes the '::' in a qualified pseudo-destructor
/// expression.
@ -1354,11 +1350,12 @@ class CXXPseudoDestructorExpr : public Expr {
/// resolve the name.
PseudoDestructorTypeStorage DestroyedType;
friend class ASTStmtReader;
public:
CXXPseudoDestructorExpr(ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
NestedNameSpecifierLoc QualifierLoc,
TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc,
SourceLocation TildeLoc,
@ -1366,36 +1363,32 @@ public:
explicit CXXPseudoDestructorExpr(EmptyShell Shell)
: Expr(CXXPseudoDestructorExprClass, Shell),
Base(0), IsArrow(false), Qualifier(0), ScopeType(0) { }
Base(0), IsArrow(false), QualifierLoc(), ScopeType(0) { }
void setBase(Expr *E) { Base = E; }
Expr *getBase() const { return cast<Expr>(Base); }
/// \brief Determines whether this member expression actually had
/// a C++ nested-name-specifier prior to the name of the member, e.g.,
/// x->Base::foo.
bool hasQualifier() const { return Qualifier != 0; }
/// \brief If the member name was qualified, retrieves the source range of
/// the nested-name-specifier that precedes the member name. Otherwise,
/// returns an empty source range.
SourceRange getQualifierRange() const { return QualifierRange; }
void setQualifierRange(SourceRange R) { QualifierRange = R; }
bool hasQualifier() const { return QualifierLoc; }
/// \brief Retrieves the nested-name-specifier that qualifies the type name,
/// with source-location information.
NestedNameSpecifierLoc getQualifierLoc() const { return QualifierLoc; }
/// \brief If the member name was qualified, retrieves the
/// nested-name-specifier that precedes the member name. Otherwise, returns
/// NULL.
NestedNameSpecifier *getQualifier() const { return Qualifier; }
void setQualifier(NestedNameSpecifier *NNS) { Qualifier = NNS; }
NestedNameSpecifier *getQualifier() const {
return QualifierLoc.getNestedNameSpecifier();
}
/// \brief Determine whether this pseudo-destructor expression was written
/// using an '->' (otherwise, it used a '.').
bool isArrow() const { return IsArrow; }
void setArrow(bool A) { IsArrow = A; }
/// \brief Retrieve the location of the '.' or '->' operator.
SourceLocation getOperatorLoc() const { return OperatorLoc; }
void setOperatorLoc(SourceLocation L) { OperatorLoc = L; }
/// \brief Retrieve the scope type in a qualified pseudo-destructor
/// expression.
@ -1407,16 +1400,13 @@ public:
/// nested-name-specifier. It is stored as the "scope type" of the pseudo-
/// destructor expression.
TypeSourceInfo *getScopeTypeInfo() const { return ScopeType; }
void setScopeTypeInfo(TypeSourceInfo *Info) { ScopeType = Info; }
/// \brief Retrieve the location of the '::' in a qualified pseudo-destructor
/// expression.
SourceLocation getColonColonLoc() const { return ColonColonLoc; }
void setColonColonLoc(SourceLocation L) { ColonColonLoc = L; }
/// \brief Retrieve the location of the '~'.
SourceLocation getTildeLoc() const { return TildeLoc; }
void setTildeLoc(SourceLocation L) { TildeLoc = L; }
/// \brief Retrieve the source location information for the type
/// being destroyed.

View File

@ -1846,7 +1846,7 @@ DEF_TRAVERSE_STMT(CXXDeleteExpr, { })
DEF_TRAVERSE_STMT(ExprWithCleanups, { })
DEF_TRAVERSE_STMT(CXXNullPtrLiteralExpr, { })
DEF_TRAVERSE_STMT(CXXPseudoDestructorExpr, {
TRY_TO(TraverseNestedNameSpecifier(S->getQualifier()));
TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
if (TypeSourceInfo *ScopeInfo = S->getScopeTypeInfo())
TRY_TO(TraverseTypeLoc(ScopeInfo->getTypeLoc()));
if (TypeSourceInfo *DestroyedTypeInfo = S->getDestroyedTypeInfo())

View File

@ -128,10 +128,10 @@ PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info)
}
CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifier *Qualifier, SourceRange QualifierRange,
TypeSourceInfo *ScopeType, SourceLocation ColonColonLoc,
SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType)
Expr *Base, bool isArrow, SourceLocation OperatorLoc,
NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType,
SourceLocation ColonColonLoc, SourceLocation TildeLoc,
PseudoDestructorTypeStorage DestroyedType)
: Expr(CXXPseudoDestructorExprClass,
Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0,
FunctionProtoType::ExtProtoInfo())),
@ -142,15 +142,16 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context,
/*isValueDependent=*/Base->isValueDependent(),
// ContainsUnexpandedParameterPack
(Base->containsUnexpandedParameterPack() ||
(Qualifier && Qualifier->containsUnexpandedParameterPack()) ||
(QualifierLoc &&
QualifierLoc.getNestedNameSpecifier()
->containsUnexpandedParameterPack()) ||
(ScopeType &&
ScopeType->getType()->containsUnexpandedParameterPack()) ||
(DestroyedType.getTypeSourceInfo() &&
DestroyedType.getTypeSourceInfo()->getType()
->containsUnexpandedParameterPack()))),
Base(static_cast<Stmt *>(Base)), IsArrow(isArrow),
OperatorLoc(OperatorLoc), Qualifier(Qualifier),
QualifierRange(QualifierRange),
OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc),
ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc),
DestroyedType(DestroyedType) { }

View File

@ -3664,7 +3664,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base,
Expr *Result
= new (Context) CXXPseudoDestructorExpr(Context, Base,
OpKind == tok::arrow, OpLoc,
SS.getScopeRep(), SS.getRange(),
SS.getWithLocInContext(Context),
ScopeTypeInfo,
CCLoc,
TildeLoc,
@ -3786,7 +3786,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base,
if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
ParsedType T = getTypeName(*FirstTypeName.Identifier,
FirstTypeName.StartLocation,
S, &SS, false, false, ObjectTypePtrForLookup);
S, &SS, true, false, ObjectTypePtrForLookup);
if (!T) {
Diag(FirstTypeName.StartLocation,
diag::err_pseudo_dtor_destructor_non_type)

View File

@ -1284,13 +1284,12 @@ public:
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
ExprResult RebuildCXXPseudoDestructorExpr(Expr *Base,
SourceLocation OperatorLoc,
bool isArrow,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
SourceLocation OperatorLoc,
bool isArrow,
CXXScopeSpec &SS,
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destroyed);
/// \brief Build a new unary operator expression.
@ -2597,9 +2596,7 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
}
}
// The object type and qualifier-in-scope really apply to the
// leftmost entity.
ObjectType = QualType();
// The qualifier-in-scope only applies to the leftmost entity.
FirstQualifierInScope = 0;
}
@ -6612,21 +6609,22 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
return ExprError();
QualType ObjectType = ObjectTypePtr.get();
NestedNameSpecifier *Qualifier = E->getQualifier();
if (Qualifier) {
Qualifier
= getDerived().TransformNestedNameSpecifier(E->getQualifier(),
E->getQualifierRange(),
ObjectType);
if (!Qualifier)
NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc();
if (QualifierLoc) {
QualifierLoc
= getDerived().TransformNestedNameSpecifierLoc(QualifierLoc, ObjectType);
if (!QualifierLoc)
return ExprError();
}
CXXScopeSpec SS;
SS.Adopt(QualifierLoc);
PseudoDestructorTypeStorage Destroyed;
if (E->getDestroyedTypeInfo()) {
TypeSourceInfo *DestroyedTypeInfo
= getDerived().TransformTypeInObjectScope(E->getDestroyedTypeInfo(),
ObjectType, 0, Qualifier);
ObjectType, 0,
QualifierLoc.getNestedNameSpecifier());
if (!DestroyedTypeInfo)
return ExprError();
Destroyed = DestroyedTypeInfo;
@ -6637,10 +6635,6 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
E->getDestroyedTypeLoc());
} else {
// Look for a destructor known with the given name.
CXXScopeSpec SS;
if (Qualifier)
SS.MakeTrivial(SemaRef.Context, Qualifier, E->getQualifierRange());
ParsedType T = SemaRef.getDestructorName(E->getTildeLoc(),
*E->getDestroyedTypeIdentifier(),
E->getDestroyedTypeLoc(),
@ -6665,8 +6659,7 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr(
return getDerived().RebuildCXXPseudoDestructorExpr(Base.get(),
E->getOperatorLoc(),
E->isArrow(),
Qualifier,
E->getQualifierRange(),
SS,
ScopeTypeInfo,
E->getColonColonLoc(),
E->getTildeLoc(),
@ -7930,16 +7923,11 @@ ExprResult
TreeTransform<Derived>::RebuildCXXPseudoDestructorExpr(Expr *Base,
SourceLocation OperatorLoc,
bool isArrow,
NestedNameSpecifier *Qualifier,
SourceRange QualifierRange,
CXXScopeSpec &SS,
TypeSourceInfo *ScopeType,
SourceLocation CCLoc,
SourceLocation TildeLoc,
PseudoDestructorTypeStorage Destroyed) {
CXXScopeSpec SS;
if (Qualifier)
SS.MakeTrivial(SemaRef.Context, Qualifier, QualifierRange);
QualType BaseType = Base->getType();
if (Base->isTypeDependent() || Destroyed.getIdentifier() ||
(!isArrow && !BaseType->getAs<RecordType>()) ||

View File

@ -1167,14 +1167,13 @@ void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
VisitExpr(E);
E->setBase(Reader.ReadSubExpr());
E->setArrow(Record[Idx++]);
E->setOperatorLoc(ReadSourceLocation(Record, Idx));
E->setQualifier(Reader.ReadNestedNameSpecifier(Record, Idx));
E->setQualifierRange(ReadSourceRange(Record, Idx));
E->setScopeTypeInfo(GetTypeSourceInfo(Record, Idx));
E->setColonColonLoc(ReadSourceLocation(Record, Idx));
E->setTildeLoc(ReadSourceLocation(Record, Idx));
E->Base = Reader.ReadSubExpr();
E->IsArrow = Record[Idx++];
E->OperatorLoc = ReadSourceLocation(Record, Idx);
E->QualifierLoc = Reader.ReadNestedNameSpecifierLoc(F, Record, Idx);
E->ScopeType = GetTypeSourceInfo(Record, Idx);
E->ColonColonLoc = ReadSourceLocation(Record, Idx);
E->TildeLoc = ReadSourceLocation(Record, Idx);
IdentifierInfo *II = Reader.GetIdentifierInfo(Record, Idx);
if (II)

View File

@ -1150,8 +1150,7 @@ void ASTStmtWriter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
Writer.AddStmt(E->getBase());
Record.push_back(E->isArrow());
Writer.AddSourceLocation(E->getOperatorLoc(), Record);
Writer.AddNestedNameSpecifier(E->getQualifier(), Record);
Writer.AddSourceRange(E->getQualifierRange(), Record);
Writer.AddNestedNameSpecifierLoc(E->getQualifierLoc(), Record);
Writer.AddTypeSourceInfo(E->getScopeTypeInfo(), Record);
Writer.AddSourceLocation(E->getColonColonLoc(), Record);
Writer.AddSourceLocation(E->getTildeLoc(), Record);

View File

@ -51,7 +51,14 @@ namespace outer {
using namespace outer_alias::inner::secret;
namespace super_secret = outer_alias::inner::secret;
// RUN: c-index-test -test-annotate-tokens=%s:13:1:53:1 %s | FileCheck %s
template<typename T>
struct X3 {
void f(T *t) {
t->::outer_alias::inner::template vector<T>::~vector<T>();
}
};
// RUN: c-index-test -test-annotate-tokens=%s:13:1:60:1 %s | FileCheck %s
// CHECK: Keyword: "using" [14:1 - 14:6] UsingDeclaration=vector[4:12]
// CHECK: Identifier: "outer_alias" [14:7 - 14:18] NamespaceRef=outer_alias:10:11
@ -120,3 +127,24 @@ namespace super_secret = outer_alias::inner::secret;
// CHECK: Identifier: "secret" [52:46 - 52:52] NamespaceRef=secret:46:15
// CHECK: Punctuation: ";" [52:52 - 52:53]
// Pseudo-destructor
// CHECK: Identifier: "t" [57:5 - 57:6] DeclRefExpr=t:56:13
// CHECK: Punctuation: "->" [57:6 - 57:8] UnexposedExpr=
// CHECK: Punctuation: "::" [57:8 - 57:10] UnexposedExpr=
// CHECK: Identifier: "outer_alias" [57:10 - 57:21] NamespaceRef=outer_alias:10:11
// CHECK: Punctuation: "::" [57:21 - 57:23] UnexposedExpr=
// CHECK: Identifier: "inner" [57:23 - 57:28] NamespaceRef=inner:45:13
// CHECK: Punctuation: "::" [57:28 - 57:30] UnexposedExpr=
// CHECK: Keyword: "template" [57:30 - 57:38] UnexposedExpr=
// CHECK: Identifier: "vector" [57:39 - 57:45] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [57:45 - 57:46] UnexposedExpr=
// CHECK: Identifier: "T" [57:46 - 57:47] UnexposedExpr=
// CHECK: Punctuation: ">" [57:47 - 57:48] UnexposedExpr=
// CHECK: Punctuation: "::" [57:48 - 57:50] UnexposedExpr=
// CHECK: Punctuation: "~" [57:50 - 57:51] UnexposedExpr=
// CHECK: Identifier: "vector" [57:51 - 57:57] TemplateRef=vector:4:12
// CHECK: Punctuation: "<" [57:57 - 57:58] UnexposedExpr=
// CHECK: Identifier: "T" [57:58 - 57:59] UnexposedExpr=
// CHECK: Punctuation: ">" [57:59 - 57:60] UnexposedExpr=
// CHECK: Punctuation: "(" [57:60 - 57:61] CallExpr=
// CHECK: Punctuation: ")" [57:61 - 57:62] CallExpr=

View File

@ -40,3 +40,24 @@ struct UnresolvedUsingTypenameDeclTester {
UnresolvedUsingTypenameDeclTester<int> UnresolvedUsingTypenameDeclCheck; // expected-note{{in instantiation of template class}}
template<typename T, typename U>
struct PseudoDestructorExprTester {
void f(T *t) {
t->T::template Inner<typename add_reference<U>::type
* // expected-error{{as a pointer to a reference of type}}
>::Blarg::~Blarg();
}
};
struct HasInnerTemplate {
template<typename T>
struct Inner;
typedef HasInnerTemplate T;
};
void PseudoDestructorExprCheck(
PseudoDestructorExprTester<HasInnerTemplate, float> tester) {
tester.f(0); // expected-note{{in instantiation of member function}}
}

View File

@ -140,6 +140,7 @@ public:
DeclRefExprPartsKind, LabelRefVisitKind,
ExplicitTemplateArgsVisitKind,
NestedNameSpecifierVisitKind,
NestedNameSpecifierLocVisitKind,
DeclarationNameInfoVisitKind,
MemberRefVisitKind, SizeOfPackExprPartsKind };
protected:
@ -1615,6 +1616,24 @@ public:
return SourceRange(A, B);
}
};
class NestedNameSpecifierLocVisit : public VisitorJob {
public:
NestedNameSpecifierLocVisit(NestedNameSpecifierLoc Qualifier, CXCursor parent)
: VisitorJob(parent, VisitorJob::NestedNameSpecifierLocVisitKind,
Qualifier.getNestedNameSpecifier(),
Qualifier.getOpaqueData()) { }
static bool classof(const VisitorJob *VJ) {
return VJ->getKind() == VisitorJob::NestedNameSpecifierLocVisitKind;
}
NestedNameSpecifierLoc get() const {
return NestedNameSpecifierLoc(static_cast<NestedNameSpecifier*>(data[0]),
data[1]);
}
};
class DeclarationNameInfoVisit : public VisitorJob {
public:
DeclarationNameInfoVisit(Stmt *S, CXCursor parent)
@ -1697,6 +1716,7 @@ public:
private:
void AddDeclarationNameInfo(Stmt *S);
void AddNestedNameSpecifier(NestedNameSpecifier *NS, SourceRange R);
void AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier);
void AddExplicitTemplateArgs(const ExplicitTemplateArgumentList *A);
void AddMemberRef(FieldDecl *D, SourceLocation L);
void AddStmt(Stmt *S);
@ -1716,6 +1736,13 @@ void EnqueueVisitor::AddNestedNameSpecifier(NestedNameSpecifier *N,
if (N)
WL.push_back(NestedNameSpecifierVisit(N, R, Parent));
}
void
EnqueueVisitor::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc Qualifier) {
if (Qualifier)
WL.push_back(NestedNameSpecifierLocVisit(Qualifier, Parent));
}
void EnqueueVisitor::AddStmt(Stmt *S) {
if (S)
WL.push_back(StmtVisit(S, Parent));
@ -1800,8 +1827,8 @@ void EnqueueVisitor::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) {
// but isn't.
AddTypeLoc(E->getScopeTypeInfo());
// Visit the nested-name-specifier.
if (NestedNameSpecifier *Qualifier = E->getQualifier())
AddNestedNameSpecifier(Qualifier, E->getQualifierRange());
if (NestedNameSpecifierLoc QualifierLoc = E->getQualifierLoc())
AddNestedNameSpecifierLoc(QualifierLoc);
// Visit base expression.
AddStmt(E->getBase());
}
@ -2048,12 +2075,21 @@ bool CursorVisitor::RunVisitorWorkList(VisitorWorkList &WL) {
}
continue;
}
case VisitorJob::NestedNameSpecifierVisitKind: {
NestedNameSpecifierVisit *V = cast<NestedNameSpecifierVisit>(&LI);
if (VisitNestedNameSpecifier(V->get(), V->getSourceRange()))
return true;
continue;
}
case VisitorJob::NestedNameSpecifierLocVisitKind: {
NestedNameSpecifierLocVisit *V = cast<NestedNameSpecifierLocVisit>(&LI);
if (VisitNestedNameSpecifierLoc(V->get()))
return true;
continue;
}
case VisitorJob::DeclarationNameInfoVisitKind: {
if (VisitDeclarationNameInfo(cast<DeclarationNameInfoVisit>(&LI)
->get()))