From b10cd04880672103660e5844e51ee91af7361a20 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sun, 21 Feb 2010 18:36:56 +0000 Subject: [PATCH] Implement support for parsing pseudo-destructor expression with a nested-name-specifier, e.g., typedef int Int; int *p; p->Int::~Int(); This weakens the invariant that the only types in nested-name-specifiers are tag types (restricted to class types in C++98/03). However, we weaken this invariant as little as possible, accepting arbitrary types in nested-name-specifiers only when we're in a member access expression that looks like a pseudo-destructor expression. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96743 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Parse/Action.h | 10 ++++++- include/clang/Parse/Parser.h | 3 +- lib/Parse/ParseExpr.cpp | 2 +- lib/Parse/ParseExprCXX.cpp | 44 ++++++++++++++++++---------- lib/Sema/Sema.h | 9 ++++-- lib/Sema/SemaCXXScopeSpec.cpp | 42 +++++++++++++++++--------- lib/Sema/SemaExprCXX.cpp | 5 ++-- lib/Sema/SemaTemplate.cpp | 1 + lib/Sema/SemaTemplateInstantiate.cpp | 2 +- lib/Sema/TreeTransform.h | 44 +++++++++++++++++++++------- test/SemaCXX/pseudo-destructors.cpp | 8 ++++- 11 files changed, 121 insertions(+), 49 deletions(-) diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 882e5d15f5..10341118e4 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -352,6 +352,11 @@ public: /// \param II the identifier that represents the scope that this /// nested-name-specifier refers to, e.g., the "bar" in "foo::bar::". /// + /// \param MayBePseudoDestructor Whether this nested-name-specifier + /// may be part of a pseudo-destructor, meaning that we are in a + /// member access expression (such as p->T::~T()) and a '~' follows + /// the '::'. + /// /// \param ObjectType if this nested-name-specifier occurs as part of a /// C++ member access expression such as "x->Base::f", the type of the base /// object (e.g., *x in the example, if "x" were a pointer). @@ -366,6 +371,7 @@ public: SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext) { return 0; @@ -380,6 +386,7 @@ public: virtual bool IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, IdentifierInfo &II, + bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext) { return false; @@ -397,7 +404,8 @@ public: const CXXScopeSpec &SS, TypeTy *Type, SourceRange TypeRange, - SourceLocation CCLoc) { + SourceLocation CCLoc, + bool MayBePseudoDestructor) { return 0; } diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f491fa895b..d21fc1f59f 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -962,7 +962,8 @@ private: bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, TypeTy *ObjectType, - bool EnteringContext); + bool EnteringContext, + bool InMemberAccessExpr = false); //===--------------------------------------------------------------------===// // C++ 5.2p1: C++ Casts diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c763c2c6f6..8105eeb875 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1001,7 +1001,7 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { OpLoc, OpKind, ObjectType); if (LHS.isInvalid()) break; - ParseOptionalCXXScopeSpecifier(SS, ObjectType, false); + ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, true); } if (Tok.is(tok::code_completion)) { diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 932d6ebf97..a8fbaff015 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -45,10 +45,14 @@ using namespace clang; /// \param EnteringContext whether we will be entering into the context of /// the nested-name-specifier after parsing it. /// +/// \param InMemberAccessExpr Whether this scope specifier is within a +/// member access expression, e.g., the \p T:: in \p p->T::m. +/// /// \returns true if a scope specifier was parsed. bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Action::TypeTy *ObjectType, - bool EnteringContext) { + bool EnteringContext, + bool InMemberAccessExpr) { assert(getLang().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -169,7 +173,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // convert it into a type within the nested-name-specifier. TemplateIdAnnotation *TemplateId = static_cast(Tok.getAnnotationValue()); - + bool MayBePseudoDestructor + = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(&SS); @@ -191,7 +196,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, TypeToken.getAnnotationValue(), TypeToken.getAnnotationRange(), - CCLoc)); + CCLoc, + MayBePseudoDestructor)); else SS.setScopeRep(0); SS.setEndLoc(CCLoc); @@ -217,18 +223,23 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // If we get foo:bar, this is almost certainly a typo for foo::bar. Recover // and emit a fixit hint for it. - if (Next.is(tok::colon) && !ColonIsSacred && - Actions.IsInvalidUnlessNestedName(CurScope, SS, II, ObjectType, - EnteringContext) && - // If the token after the colon isn't an identifier, it's still an - // error, but they probably meant something else strange so don't - // recover like this. - PP.LookAhead(1).is(tok::identifier)) { - Diag(Next, diag::err_unexected_colon_in_nested_name_spec) - << CodeModificationHint::CreateReplacement(Next.getLocation(), "::"); + if (Next.is(tok::colon) && !ColonIsSacred) { + bool MayBePseudoDestructor + = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde); - // Recover as if the user wrote '::'. - Next.setKind(tok::coloncolon); + if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, + MayBePseudoDestructor, ObjectType, + EnteringContext) && + // If the token after the colon isn't an identifier, it's still an + // error, but they probably meant something else strange so don't + // recover like this. + PP.LookAhead(1).is(tok::identifier)) { + Diag(Next, diag::err_unexected_colon_in_nested_name_spec) + << CodeModificationHint::CreateReplacement(Next.getLocation(), "::"); + + // Recover as if the user wrote '::'. + Next.setKind(tok::coloncolon); + } } if (Next.is(tok::coloncolon)) { @@ -247,9 +258,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, if (SS.isInvalid()) continue; + bool MayBePseudoDestructor = InMemberAccessExpr && Tok.is(tok::tilde); + SS.setScopeRep( Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II, - ObjectType, EnteringContext)); + MayBePseudoDestructor, ObjectType, + EnteringContext)); SS.setEndLoc(CCLoc); continue; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 25ca3d1144..4ea379328c 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2198,7 +2198,8 @@ public: virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S, SourceLocation CCLoc); - bool isAcceptableNestedNameSpecifier(NamedDecl *SD); + bool isAcceptableNestedNameSpecifier(NamedDecl *SD, + bool MayBePseudoDestructor = false); NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS); @@ -2207,6 +2208,7 @@ public: SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *ScopeLookupResult, bool EnteringContext, @@ -2217,12 +2219,14 @@ public: SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext); virtual bool IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, IdentifierInfo &II, + bool MayBePseudoDestructor, TypeTy *ObjectType, bool EnteringContext); @@ -2238,7 +2242,8 @@ public: const CXXScopeSpec &SS, TypeTy *Type, SourceRange TypeRange, - SourceLocation CCLoc); + SourceLocation CCLoc, + bool MayBePseudoDestructor); virtual bool ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS); diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 52e9e9bc87..315938d2d4 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -176,16 +176,15 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - const TagType *Tag = NNS->getAsType()->getAs(); - assert(Tag && "Non-tag type in nested-name-specifier"); - return Tag->getDecl(); - } break; + if (const TagType *Tag = NNS->getAsType()->getAs()) + return Tag->getDecl(); + break; + } case NestedNameSpecifier::Global: return Context.getTranslationUnitDecl(); } - // Required to silence a GCC warning. return 0; } @@ -270,7 +269,8 @@ Sema::CXXScopeTy *Sema::ActOnCXXGlobalScopeSpecifier(Scope *S, /// \brief Determines whether the given declaration is an valid acceptable /// result for name lookup of a nested-name-specifier. -bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) { +bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD, + bool MayBePseudoDestructor) { if (!SD) return false; @@ -281,6 +281,11 @@ bool Sema::isAcceptableNestedNameSpecifier(NamedDecl *SD) { if (!isa(SD)) return false; + // If this may be part of a pseudo-destructor expression, we'll + // accept any type. + if (MayBePseudoDestructor) + return true; + // Determine whether we have a class (or, in C++0x, an enum) or // a typedef thereof. If so, build the nested-name-specifier. QualType T = Context.getTypeDeclType(cast(SD)); @@ -321,7 +326,7 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { return 0; NamedDecl *Result = Found.getFoundDecl(); - if (isAcceptableNestedNameSpecifier(Result)) + if (isAcceptableNestedNameSpecifier(Result, true)) return Result; return 0; @@ -345,6 +350,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *ScopeLookupResult, bool EnteringContext, @@ -439,7 +445,8 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, DeclarationName Name = Found.getLookupName(); if (CorrectTypo(Found, S, &SS, LookupCtx, EnteringContext) && Found.isSingleResult() && - isAcceptableNestedNameSpecifier(Found.getAsSingle())) { + isAcceptableNestedNameSpecifier(Found.getAsSingle(), + MayBePseudoDestructor)) { if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << Found.getLookupName() << SS.getRange() @@ -459,7 +466,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, } NamedDecl *SD = Found.getAsSingle(); - if (isAcceptableNestedNameSpecifier(SD)) { + if (isAcceptableNestedNameSpecifier(SD, MayBePseudoDestructor)) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope) { // C++ [basic.lookup.classref]p4: // [...] If the name is found in both contexts, the @@ -471,13 +478,14 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, // scope, reconstruct the result from the template instantiation itself. NamedDecl *OuterDecl; if (S) { - LookupResult FoundOuter(*this, &II, IdLoc, LookupNestedNameSpecifierName); + LookupResult FoundOuter(*this, &II, IdLoc, + LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle(); } else OuterDecl = ScopeLookupResult; - if (isAcceptableNestedNameSpecifier(OuterDecl) && + if (isAcceptableNestedNameSpecifier(OuterDecl, MayBePseudoDestructor) && OuterDecl->getCanonicalDecl() != SD->getCanonicalDecl() && (!isa(OuterDecl) || !isa(SD) || !Context.hasSameType( @@ -554,9 +562,11 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, SourceLocation IdLoc, SourceLocation CCLoc, IdentifierInfo &II, + bool MayBePseudoDestructor, TypeTy *ObjectTypePtr, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, IdLoc, CCLoc, II, + MayBePseudoDestructor, QualType::getFromOpaquePtr(ObjectTypePtr), /*ScopeLookupResult=*/0, EnteringContext, false); @@ -569,10 +579,13 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. bool Sema::IsInvalidUnlessNestedName(Scope *S, const CXXScopeSpec &SS, - IdentifierInfo &II, TypeTy *ObjectType, + IdentifierInfo &II, + bool MayBePseudoDestructor, + TypeTy *ObjectType, bool EnteringContext) { return BuildCXXNestedNameSpecifier(S, SS, SourceLocation(), SourceLocation(), - II, QualType::getFromOpaquePtr(ObjectType), + II, MayBePseudoDestructor, + QualType::getFromOpaquePtr(ObjectType), /*ScopeLookupResult=*/0, EnteringContext, true); } @@ -581,7 +594,8 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS, TypeTy *Ty, SourceRange TypeRange, - SourceLocation CCLoc) { + SourceLocation CCLoc, + bool MayBePseudoDestructor) { NestedNameSpecifier *Prefix = static_cast(SS.getScopeRep()); QualType T = GetTypeFromParser(Ty); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 4cb58d8d19..7e32f17131 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -85,10 +85,11 @@ Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, isDependent = SearchType->isDependentType(); } else { LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = LookupCtx->isDependentContext(); + if (LookupCtx) + isDependent = LookupCtx->isDependentContext(); } - LookInScope = false; + LookInScope = (LookupCtx == 0) && !isDependent; } else if (ObjectTypePtr) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c98f88f86a..0d5c50ab1b 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4925,6 +4925,7 @@ CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), /*FIXME:*/SourceRange(getBaseLocation()), + false, ObjectType); if (!NNS) return QualType(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index f12c559ec1..b6ddc46347 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -1486,7 +1486,7 @@ Sema::SubstNestedNameSpecifier(NestedNameSpecifier *NNS, const MultiLevelTemplateArgumentList &TemplateArgs) { TemplateInstantiator Instantiator(*this, TemplateArgs, Range.getBegin(), DeclarationName()); - return Instantiator.TransformNestedNameSpecifier(NNS, Range); + return Instantiator.TransformNestedNameSpecifier(NNS, Range, false); } TemplateName diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index a59608661c..11c19eb23c 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -265,6 +265,7 @@ public: /// alternate behavior. NestedNameSpecifier *TransformNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range, + bool MayBePseudoDestructor, QualType ObjectType = QualType(), NamedDecl *FirstQualifierInScope = 0); @@ -555,6 +556,7 @@ public: NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, IdentifierInfo &II, + bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *FirstQualifierInScope); @@ -577,7 +579,8 @@ public: NestedNameSpecifier *RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, bool TemplateKW, - QualType T); + QualType T, + bool MayBePseudoDestructor); /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template @@ -1725,6 +1728,7 @@ template NestedNameSpecifier * TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, SourceRange Range, + bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *FirstQualifierInScope) { if (!NNS) @@ -1734,6 +1738,7 @@ TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, NestedNameSpecifier *Prefix = NNS->getPrefix(); if (Prefix) { Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range, + false, ObjectType, FirstQualifierInScope); if (!Prefix) @@ -1755,6 +1760,7 @@ TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, return getDerived().RebuildNestedNameSpecifier(Prefix, Range, *NNS->getAsIdentifier(), + MayBePseudoDestructor, ObjectType, FirstQualifierInScope); @@ -1790,7 +1796,8 @@ TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, return getDerived().RebuildNestedNameSpecifier(Prefix, Range, NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T); + T, + MayBePseudoDestructor); } } @@ -1842,6 +1849,7 @@ TreeTransform::TransformTemplateName(TemplateName Name, NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), /*FIXME:*/SourceRange(getDerived().getBaseLocation()), + false, ObjectType); if (!NNS) return TemplateName(); @@ -1869,6 +1877,7 @@ TreeTransform::TransformTemplateName(TemplateName Name, NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), /*FIXME:*/SourceRange(getDerived().getBaseLocation()), + false, ObjectType); if (!NNS && DTN->getQualifier()) return TemplateName(); @@ -2928,6 +2937,7 @@ TreeTransform::TransformQualifiedNameType(TypeLocBuilder &TLB, NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SourceRange(), + false, ObjectType); if (!NNS) return QualType(); @@ -2962,7 +2972,7 @@ QualType TreeTransform::TransformTypenameType(TypeLocBuilder &TLB, NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR, - ObjectType); + false, ObjectType); if (!NNS) return QualType(); @@ -3598,7 +3608,8 @@ TreeTransform::TransformDeclRefExpr(DeclRefExpr *E) { NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + E->getQualifierRange(), + false); if (!Qualifier) return SemaRef.ExprError(); } @@ -3807,7 +3818,8 @@ TreeTransform::TransformMemberExpr(MemberExpr *E) { if (E->hasQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + E->getQualifierRange(), + false); if (Qualifier == 0) return SemaRef.ExprError(); } @@ -4677,7 +4689,8 @@ TreeTransform::TransformCXXPseudoDestructorExpr( NestedNameSpecifier *Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + E->getQualifierRange(), + true); if (E->getQualifier() && !Qualifier) return SemaRef.ExprError(); @@ -4747,7 +4760,8 @@ TreeTransform::TransformUnresolvedLookupExpr( NestedNameSpecifier *Qualifier = 0; if (Old->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), - Old->getQualifierRange()); + Old->getQualifierRange(), + false); if (!Qualifier) return SemaRef.ExprError(); @@ -4803,7 +4817,8 @@ TreeTransform::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(E->getQualifier(), - E->getQualifierRange()); + E->getQualifierRange(), + false); if (!NNS) return SemaRef.ExprError(); @@ -5050,8 +5065,11 @@ TreeTransform::TransformCXXDependentScopeMemberExpr( NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { + bool MayBePseudoDestructor + = E->getMember().getNameKind() == DeclarationName::CXXDestructorName; Qualifier = getDerived().TransformNestedNameSpecifier(E->getQualifier(), E->getQualifierRange(), + MayBePseudoDestructor, ObjectType, FirstQualifierInScope); if (!Qualifier) @@ -5126,7 +5144,8 @@ TreeTransform::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) if (Old->getQualifier()) { Qualifier = getDerived().TransformNestedNameSpecifier(Old->getQualifier(), - Old->getQualifierRange()); + Old->getQualifierRange(), + false); if (Qualifier == 0) return SemaRef.ExprError(); } @@ -5551,6 +5570,7 @@ NestedNameSpecifier * TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, IdentifierInfo &II, + bool MayBePseudoDestructor, QualType ObjectType, NamedDecl *FirstQualifierInScope) { CXXScopeSpec SS; @@ -5560,6 +5580,7 @@ TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, return static_cast( SemaRef.BuildCXXNestedNameSpecifier(0, SS, Range.getEnd(), Range.getEnd(), II, + MayBePseudoDestructor, ObjectType, FirstQualifierInScope, false, false)); @@ -5578,8 +5599,9 @@ NestedNameSpecifier * TreeTransform::RebuildNestedNameSpecifier(NestedNameSpecifier *Prefix, SourceRange Range, bool TemplateKW, - QualType T) { - if (T->isDependentType() || T->isRecordType() || + QualType T, + bool MayBePseudoDestructor) { + if (MayBePseudoDestructor || T->isDependentType() || T->isRecordType() || (SemaRef.getLangOptions().CPlusPlus0x && T->isEnumeralType())) { assert(!T.hasLocalQualifiers() && "Can't get cv-qualifiers here"); return NestedNameSpecifier::Create(SemaRef.Context, Prefix, TemplateKW, diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp index 02e2c14ca1..2cc233318e 100644 --- a/test/SemaCXX/pseudo-destructors.cpp +++ b/test/SemaCXX/pseudo-destructors.cpp @@ -5,6 +5,7 @@ enum Foo { F }; typedef Foo Bar; typedef int Integer; +typedef double Double; void g(); @@ -12,7 +13,7 @@ namespace N { typedef Foo Wibble; } -void f(A* a, Foo *f, int *i) { +void f(A* a, Foo *f, int *i, double *d) { a->~A(); a->A::~A(); @@ -31,6 +32,11 @@ void f(A* a, Foo *f, int *i) { f->N::~Wibble(); // FIXME: Cannot use typedef name in destructor id. f->::~Bar(17, 42); // expected-error{{cannot have any arguments}} + + i->~Integer(); + i->Integer::~Integer(); + + i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('double') in pseudo-destructor expression}} } typedef int Integer; -- 2.40.0