From 124b878dba5007df0a268ea128a6ad8dc5dd2c5e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 16 Feb 2010 19:09:40 +0000 Subject: [PATCH] Improve parsing and instantiation of destructor names, so that we can now cope with the destruction of types named as dependent templates, e.g., y->template Y::~Y() Nominally, we implement C++0x [basic.lookup.qual]p6. However, we don't follow the letter of the standard here because that would fail to parse template X0::~X0() { } properly. The problem is captured in core issue 339, which gives some (but not enough!) guidance. I expect to revisit this code when the resolution of 339 is clear, and/or we start capturing better source information for DeclarationNames. Fixes PR6152. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96367 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 8 +- include/clang/Basic/DiagnosticSemaKinds.td | 4 + include/clang/Parse/Action.h | 14 +- include/clang/Parse/Parser.h | 3 +- lib/Parse/ParseDeclCXX.cpp | 6 +- lib/Parse/ParseExprCXX.cpp | 27 +-- lib/Sema/Sema.h | 6 + lib/Sema/SemaExprCXX.cpp | 226 ++++++++++++++++++++ lib/Sema/SemaTemplate.cpp | 9 +- lib/Sema/SemaTemplateInstantiate.cpp | 6 +- lib/Sema/TreeTransform.h | 171 ++++++++------- test/SemaCXX/destructor.cpp | 4 +- test/SemaCXX/invalid-member-expr.cpp | 4 +- test/SemaCXX/pseudo-destructors.cpp | 6 +- test/SemaTemplate/destructor-template.cpp | 13 ++ 15 files changed, 394 insertions(+), 113 deletions(-) diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index bc26c3b0da..4b8ed44783 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -146,8 +146,6 @@ def err_missing_comma_before_ellipsis : Error< def err_unexpected_typedef_ident : Error< "unexpected type name %0: expected identifier">; def err_expected_class_name : Error<"expected class name">; -def err_destructor_class_name : Error< - "expected the class name after '~' to name a destructor">; def err_unspecified_vla_size_with_static : Error< "'static' may not be used with an unspecified variable length array size">; @@ -247,8 +245,10 @@ def err_expected_catch : Error<"expected catch">; def err_expected_lbrace_or_comma : Error<"expected '{' or ','">; def err_using_namespace_in_class : Error< "'using namespace' is not allowed in classes">; -def err_ident_in_pseudo_dtor_not_a_type : Error< - "identifier %0 in pseudo-destructor expression does not name a type">; +def err_destructor_tilde_identifier : Error< + "expected a class name after '~' to name a destructor">; +def err_destructor_template_id : Error< + "destructor name %0 does not refer to a template">; // C++ derived classes def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 19b242e86b..bc834a8478 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -557,6 +557,10 @@ def err_destructor_typedef_name : Error< "destructor cannot be declared using a typedef %0 of the class name">; def err_destructor_name : Error< "expected the class name after '~' to name the enclosing class">; +def err_destructor_class_name : Error< + "expected the class name after '~' to name a destructor">; +def err_ident_in_pseudo_dtor_not_a_type : Error< + "identifier %0 in pseudo-destructor expression does not name a type">; // C++ initialization def err_init_conversion_failed : Error< diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index ec542f08c3..882e5d15f5 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1075,7 +1075,7 @@ public: SourceLocation RLoc) { return ExprEmpty(); } - + /// \brief Parsed a member access expresion (C99 6.5.2.3, C++ [expr.ref]) /// of the form \c x.m or \c p->m. /// @@ -1473,6 +1473,18 @@ public: //===------------------------- C++ Expressions --------------------------===// + /// \brief Parsed a destructor name or pseudo-destructor name. + /// + /// \returns the type being destructed. + virtual TypeTy *getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec &SS, + TypeTy *ObjectType, + bool EnteringContext) { + return getTypeName(II, NameLoc, S, &SS, false, ObjectType); + } + + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index f4d3d3e54d..f491fa895b 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1387,8 +1387,7 @@ private: //===--------------------------------------------------------------------===// // C++ 9: classes [class] and C structs/unions. TypeResult ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS = 0, - bool DestrExpected = false); + const CXXScopeSpec *SS = 0); void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc, DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(), diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 51ee6a4434..225ce256b1 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -464,8 +464,7 @@ void Parser::ParseDecltypeSpecifier(DeclSpec &DS) { /// simple-template-id /// Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, - const CXXScopeSpec *SS, - bool DestrExpected) { + const CXXScopeSpec *SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId @@ -536,8 +535,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, // We have an identifier; check whether it is actually a type. TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true); if (!Type) { - Diag(IdLoc, DestrExpected ? diag::err_destructor_class_name - : diag::err_expected_class_name); + Diag(IdLoc, diag::err_expected_class_name); return true; } diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 0dbe1ea838..932d6ebf97 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -846,13 +846,8 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, EnteringContext, Template); if (TNK == TNK_Non_template && Id.DestructorName == 0) { - // The identifier following the destructor did not refer to a template - // or to a type. Complain. - if (ObjectType) - Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << Name; - else - Diag(NameLoc, diag::err_destructor_class_name); + Diag(NameLoc, diag::err_destructor_template_id) + << Name << SS.getRange(); return true; } } @@ -1258,7 +1253,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // Parse the class-name. if (Tok.isNot(tok::identifier)) { - Diag(Tok, diag::err_destructor_class_name); + Diag(Tok, diag::err_destructor_tilde_identifier); return true; } @@ -1273,17 +1268,13 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, } // Note that this is a destructor name. - Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc, - CurScope, &SS, false, ObjectType); - if (!Ty) { - if (ObjectType) - Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) - << ClassName; - else - Diag(ClassNameLoc, diag::err_destructor_class_name); + Action::TypeTy *Ty = Actions.getDestructorName(TildeLoc, *ClassName, + ClassNameLoc, CurScope, + SS, ObjectType, + EnteringContext); + if (!Ty) return true; - } - + Result.setDestructorName(TildeLoc, Ty, ClassNameLoc); return false; } diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3c0adbe6b0..25ca3d1144 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2056,6 +2056,12 @@ public: SourceLocation Loc, ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs); + virtual TypeTy *getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, SourceLocation NameLoc, + Scope *S, const CXXScopeSpec &SS, + TypeTy *ObjectType, + bool EnteringContext); + /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 9eeda54299..4098d0f2cf 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -24,6 +24,232 @@ #include "llvm/ADT/STLExtras.h" using namespace clang; +Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc, + IdentifierInfo &II, + SourceLocation NameLoc, + Scope *S, const CXXScopeSpec &SS, + TypeTy *ObjectTypePtr, + bool EnteringContext) { + // Determine where to perform name lookup. + + // FIXME: This area of the standard is very messy, and the current + // wording is rather unclear about which scopes we search for the + // destructor name; see core issues 399 and 555. Issue 399 in + // particular shows where the current description of destructor name + // lookup is completely out of line with existing practice, e.g., + // this appears to be ill-formed: + // + // namespace N { + // template struct S { + // ~S(); + // }; + // } + // + // void f(N::S* s) { + // s->N::S::~S(); + // } + // + // + QualType SearchType; + DeclContext *LookupCtx = 0; + bool isDependent = false; + bool LookInScope = false; + + // If we have an object type, it's because we are in a + // pseudo-destructor-expression or a member access expression, and + // we know what type we're looking for. + if (ObjectTypePtr) + SearchType = GetTypeFromParser(ObjectTypePtr); + + if (SS.isSet()) { + // C++ [basic.lookup.qual]p6: + // If a pseudo-destructor-name (5.2.4) contains a + // nested-name-specifier, the type-names are looked up as types + // in the scope designated by the nested-name-specifier. Similarly, in + // a qualified-id of theform: + // + // :: [opt] nested-name-specifier[opt] class-name :: ~class-name + // + // the second class-name is looked up in the same scope as the first. + // + // To implement this, we look at the prefix of the + // nested-name-specifier we were given, and determine the lookup + // context from that. + NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + if (NestedNameSpecifier *Prefix = NNS->getPrefix()) { + CXXScopeSpec PrefixSS; + PrefixSS.setScopeRep(Prefix); + LookupCtx = computeDeclContext(PrefixSS, EnteringContext); + isDependent = isDependentScopeSpecifier(PrefixSS); + } else if (ObjectTypePtr) { + LookupCtx = computeDeclContext(SearchType); + isDependent = SearchType->isDependentType(); + } else { + LookupCtx = computeDeclContext(SS, EnteringContext); + if (LookupCtx && !LookupCtx->isTranslationUnit()) { + LookupCtx = LookupCtx->getParent(); + isDependent = LookupCtx->isDependentContext(); + } else { + isDependent = false; + } + } + + LookInScope = false; + } else if (ObjectTypePtr) { + // C++ [basic.lookup.classref]p3: + // If the unqualified-id is ~type-name, the type-name is looked up + // in the context of the entire postfix-expression. If the type T + // of the object expression is of a class type C, the type-name is + // also looked up in the scope of class C. At least one of the + // lookups shall find a name that refers to (possibly + // cv-qualified) T. + LookupCtx = computeDeclContext(SearchType); + isDependent = SearchType->isDependentType(); + assert((isDependent || !SearchType->isIncompleteType()) && + "Caller should have completed object type"); + + LookInScope = true; + } else { + // Perform lookup into the current scope (only). + LookInScope = true; + } + + LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); + for (unsigned Step = 0; Step != 2; ++Step) { + // Look for the name first in the computed lookup context (if we + // have one) and, if that fails to find a match, in the sope (if + // we're allowed to look there). + Found.clear(); + if (Step == 0 && LookupCtx) + LookupQualifiedName(Found, LookupCtx); + else if (Step == 1 && LookInScope) + LookupName(Found, S); + else + continue; + + // FIXME: Should we be suppressing ambiguities here? + if (Found.isAmbiguous()) + return 0; + + if (TypeDecl *Type = Found.getAsSingle()) { + QualType T = Context.getTypeDeclType(Type); + // If we found the injected-class-name of a class template, retrieve the + // type of that template. + // FIXME: We really shouldn't need to do this. + if (CXXRecordDecl *Record = dyn_cast(Type)) + if (Record->isInjectedClassName()) + if (Record->getDescribedClassTemplate()) + T = Record->getDescribedClassTemplate() + ->getInjectedClassNameType(Context); + + if (SearchType.isNull() || SearchType->isDependentType() || + Context.hasSameUnqualifiedType(T, SearchType)) { + // We found our type! + + return T.getAsOpaquePtr(); + } + } + + // If the name that we found is a class template name, and it is + // the same name as the template name in the last part of the + // nested-name-specifier (if present) or the object type, then + // this is the destructor for that class. + // FIXME: This is a workaround until we get real drafting for core + // issue 399, for which there isn't even an obvious direction. + if (ClassTemplateDecl *Template = Found.getAsSingle()) { + QualType MemberOfType; + if (SS.isSet()) { + if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { + // Figure out the type of the context, if it has one. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(Ctx)) + MemberOfType = Context.getTypeDeclType(Spec); + else if (CXXRecordDecl *Record = dyn_cast(Ctx)) { + if (Record->getDescribedClassTemplate()) + MemberOfType = Record->getDescribedClassTemplate() + ->getInjectedClassNameType(Context); + else + MemberOfType = Context.getTypeDeclType(Record); + } + } + } + if (MemberOfType.isNull()) + MemberOfType = SearchType; + + if (MemberOfType.isNull()) + continue; + + // We're referring into a class template specialization. If the + // class template we found is the same as the template being + // specialized, we found what we are looking for. + if (const RecordType *Record = MemberOfType->getAs()) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(Record->getDecl())) { + if (Spec->getSpecializedTemplate()->getCanonicalDecl() == + Template->getCanonicalDecl()) + return MemberOfType.getAsOpaquePtr(); + } + + continue; + } + + // We're referring to an unresolved class template + // specialization. Determine whether we class template we found + // is the same as the template being specialized or, if we don't + // know which template is being specialized, that it at least + // has the same name. + if (const TemplateSpecializationType *SpecType + = MemberOfType->getAs()) { + TemplateName SpecName = SpecType->getTemplateName(); + + // The class template we found is the same template being + // specialized. + if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { + if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) + return MemberOfType.getAsOpaquePtr(); + + continue; + } + + // The class template we found has the same name as the + // (dependent) template name being specialized. + if (DependentTemplateName *DepTemplate + = SpecName.getAsDependentTemplateName()) { + if (DepTemplate->isIdentifier() && + DepTemplate->getIdentifier() == Template->getIdentifier()) + return MemberOfType.getAsOpaquePtr(); + + continue; + } + } + } + } + + if (isDependent) { + // We didn't find our type, but that's okay: it's dependent + // anyway. + NestedNameSpecifier *NNS = 0; + SourceRange Range; + if (SS.isSet()) { + NNS = (NestedNameSpecifier *)SS.getScopeRep(); + Range = SourceRange(SS.getRange().getBegin(), NameLoc); + } else { + NNS = NestedNameSpecifier::Create(Context, &II); + Range = SourceRange(NameLoc); + } + + return CheckTypenameType(NNS, II, Range).getAsOpaquePtr(); + } + + if (ObjectTypePtr) + Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) + << &II; + else + Diag(NameLoc, diag::err_destructor_class_name); + + return 0; +} + /// ActOnCXXTypeidOfType - Parse typeid( type-id ). Action::OwningExprResult Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 10e411f582..c98f88f86a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -4911,18 +4911,21 @@ namespace { /// \brief Transforms a typename type by determining whether the type now /// refers to a member of the current instantiation, and then /// type-checking and building a QualifiedNameType (when possible). - QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL); + QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL, + QualType ObjectType); }; } QualType CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL) { + TypenameTypeLoc TL, + QualType ObjectType) { TypenameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = TransformNestedNameSpecifier(T->getQualifier(), - /*FIXME:*/SourceRange(getBaseLocation())); + /*FIXME:*/SourceRange(getBaseLocation()), + ObjectType); if (!NNS) return QualType(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 51e17fe472..f12c559ec1 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -570,7 +570,8 @@ namespace { /// \brief Transforms a template type parameter type by performing /// substitution of the corresponding template type argument. QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL); + TemplateTypeParmTypeLoc TL, + QualType ObjectType); }; } @@ -859,7 +860,8 @@ Sema::OwningExprResult TemplateInstantiator::TransformCXXDefaultArgExpr( QualType TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + QualType ObjectType) { TemplateTypeParmType *T = TL.getTypePtr(); if (T->getDepth() < TemplateArgs.getNumLevels()) { // Replace the template type parameter with its corresponding diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index fc069f7ba3..a59608661c 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -191,7 +191,7 @@ public: /// switched to storing TypeSourceInfos. /// /// \returns the transformed type. - QualType TransformType(QualType T); + QualType TransformType(QualType T, QualType ObjectType = QualType()); /// \brief Transforms the given type-with-location into a new /// type-with-location. @@ -201,13 +201,15 @@ public: /// may override this function (to take over all type /// transformations) or some set of the TransformXXXType functions /// to alter the transformation. - TypeSourceInfo *TransformType(TypeSourceInfo *DI); + TypeSourceInfo *TransformType(TypeSourceInfo *DI, + QualType ObjectType = QualType()); /// \brief Transform the given type-with-location into a new /// type, collecting location information in the given builder /// as necessary. /// - QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL); + QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL, + QualType ObjectType = QualType()); /// \brief Transform the given statement. /// @@ -307,20 +309,17 @@ public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ - QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T); + QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T, \ + QualType ObjectType = QualType()); #include "clang/AST/TypeLocNodes.def" - QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL); + QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, + QualType ObjectType); QualType TransformTemplateSpecializationType(const TemplateSpecializationType *T, QualType ObjectType); - QualType - TransformTemplateSpecializationType(TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL, - QualType ObjectType); - OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ @@ -1779,7 +1778,8 @@ TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::TypeSpec: { TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName()); - QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0)); + QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0), + ObjectType); if (T.isNull()) return 0; @@ -1820,14 +1820,8 @@ TreeTransform::TransformDeclarationName(DeclarationName Name, case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { TemporaryBase Rebase(*this, Loc, Name); - QualType T; - if (!ObjectType.isNull() && - isa(Name.getCXXNameType())) { - TemplateSpecializationType *SpecType - = cast(Name.getCXXNameType()); - T = TransformTemplateSpecializationType(SpecType, ObjectType); - } else - T = getDerived().TransformType(Name.getCXXNameType()); + QualType T = getDerived().TransformType(Name.getCXXNameType(), + ObjectType); if (T.isNull()) return DeclarationName(); @@ -1847,7 +1841,8 @@ TreeTransform::TransformTemplateName(TemplateName Name, if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(), - /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + /*FIXME:*/SourceRange(getDerived().getBaseLocation()), + ObjectType); if (!NNS) return TemplateName(); @@ -1873,7 +1868,8 @@ TreeTransform::TransformTemplateName(TemplateName Name, if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(), - /*FIXME:*/SourceRange(getDerived().getBaseLocation())); + /*FIXME:*/SourceRange(getDerived().getBaseLocation()), + ObjectType); if (!NNS && DTN->getQualifier()) return TemplateName(); @@ -2055,7 +2051,8 @@ bool TreeTransform::TransformTemplateArgument( //===----------------------------------------------------------------------===// template -QualType TreeTransform::TransformType(QualType T) { +QualType TreeTransform::TransformType(QualType T, + QualType ObjectType) { if (getDerived().AlreadyTransformed(T)) return T; @@ -2064,7 +2061,7 @@ QualType TreeTransform::TransformType(QualType T) { TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T); DI->getTypeLoc().initialize(getDerived().getBaseLocation()); - TypeSourceInfo *NewDI = getDerived().TransformType(DI); + TypeSourceInfo *NewDI = getDerived().TransformType(DI, ObjectType); if (!NewDI) return QualType(); @@ -2073,7 +2070,8 @@ QualType TreeTransform::TransformType(QualType T) { } template -TypeSourceInfo *TreeTransform::TransformType(TypeSourceInfo *DI) { +TypeSourceInfo *TreeTransform::TransformType(TypeSourceInfo *DI, + QualType ObjectType) { if (getDerived().AlreadyTransformed(DI->getType())) return DI; @@ -2082,7 +2080,7 @@ TypeSourceInfo *TreeTransform::TransformType(TypeSourceInfo *DI) { TypeLoc TL = DI->getTypeLoc(); TLB.reserve(TL.getFullDataSize()); - QualType Result = getDerived().TransformType(TLB, TL); + QualType Result = getDerived().TransformType(TLB, TL, ObjectType); if (Result.isNull()) return 0; @@ -2091,12 +2089,14 @@ TypeSourceInfo *TreeTransform::TransformType(TypeSourceInfo *DI) { template QualType -TreeTransform::TransformType(TypeLocBuilder &TLB, TypeLoc T) { +TreeTransform::TransformType(TypeLocBuilder &TLB, TypeLoc T, + QualType ObjectType) { switch (T.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case TypeLoc::CLASS: \ - return getDerived().Transform##CLASS##Type(TLB, cast(T)); + return getDerived().Transform##CLASS##Type(TLB, cast(T), \ + ObjectType); #include "clang/AST/TypeLocNodes.def" } @@ -2112,10 +2112,12 @@ TreeTransform::TransformType(TypeLocBuilder &TLB, TypeLoc T) { template QualType TreeTransform::TransformQualifiedType(TypeLocBuilder &TLB, - QualifiedTypeLoc T) { + QualifiedTypeLoc T, + QualType ObjectType) { Qualifiers Quals = T.getType().getLocalQualifiers(); - QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc()); + QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc(), + ObjectType); if (Result.isNull()) return QualType(); @@ -2166,7 +2168,8 @@ QualType TransformTypeSpecType(TypeLocBuilder &TLB, TyLoc T) { template QualType TreeTransform::TransformBuiltinType(TypeLocBuilder &TLB, - BuiltinTypeLoc T) { + BuiltinTypeLoc T, + QualType ObjectType) { BuiltinTypeLoc NewT = TLB.push(T.getType()); NewT.setBuiltinLoc(T.getBuiltinLoc()); if (T.needsExtraLocalData()) @@ -2176,21 +2179,24 @@ QualType TreeTransform::TransformBuiltinType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformComplexType(TypeLocBuilder &TLB, - ComplexTypeLoc T) { + ComplexTypeLoc T, + QualType ObjectType) { // FIXME: recurse? return TransformTypeSpecType(TLB, T); } template QualType TreeTransform::TransformPointerType(TypeLocBuilder &TLB, - PointerTypeLoc TL) { + PointerTypeLoc TL, + QualType ObjectType) { TransformPointerLikeType(PointerType); } template QualType TreeTransform::TransformBlockPointerType(TypeLocBuilder &TLB, - BlockPointerTypeLoc TL) { + BlockPointerTypeLoc TL, + QualType ObjectType) { TransformPointerLikeType(BlockPointerType); } @@ -2201,7 +2207,8 @@ TreeTransform::TransformBlockPointerType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformReferenceType(TypeLocBuilder &TLB, - ReferenceTypeLoc TL) { + ReferenceTypeLoc TL, + QualType ObjectType) { const ReferenceType *T = TL.getTypePtr(); // Note that this works with the pointee-as-written. @@ -2233,21 +2240,24 @@ TreeTransform::TransformReferenceType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformLValueReferenceType(TypeLocBuilder &TLB, - LValueReferenceTypeLoc TL) { - return TransformReferenceType(TLB, TL); + LValueReferenceTypeLoc TL, + QualType ObjectType) { + return TransformReferenceType(TLB, TL, ObjectType); } template QualType TreeTransform::TransformRValueReferenceType(TypeLocBuilder &TLB, - RValueReferenceTypeLoc TL) { - return TransformReferenceType(TLB, TL); + RValueReferenceTypeLoc TL, + QualType ObjectType) { + return TransformReferenceType(TLB, TL, ObjectType); } template QualType TreeTransform::TransformMemberPointerType(TypeLocBuilder &TLB, - MemberPointerTypeLoc TL) { + MemberPointerTypeLoc TL, + QualType ObjectType) { MemberPointerType *T = TL.getTypePtr(); QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc()); @@ -2279,7 +2289,8 @@ TreeTransform::TransformMemberPointerType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformConstantArrayType(TypeLocBuilder &TLB, - ConstantArrayTypeLoc TL) { + ConstantArrayTypeLoc TL, + QualType ObjectType) { ConstantArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2314,7 +2325,8 @@ TreeTransform::TransformConstantArrayType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformIncompleteArrayType( TypeLocBuilder &TLB, - IncompleteArrayTypeLoc TL) { + IncompleteArrayTypeLoc TL, + QualType ObjectType) { IncompleteArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2342,7 +2354,8 @@ QualType TreeTransform::TransformIncompleteArrayType( template QualType TreeTransform::TransformVariableArrayType(TypeLocBuilder &TLB, - VariableArrayTypeLoc TL) { + VariableArrayTypeLoc TL, + QualType ObjectType) { VariableArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2383,7 +2396,8 @@ TreeTransform::TransformVariableArrayType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformDependentSizedArrayType(TypeLocBuilder &TLB, - DependentSizedArrayTypeLoc TL) { + DependentSizedArrayTypeLoc TL, + QualType ObjectType) { DependentSizedArrayType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc()); if (ElementType.isNull()) @@ -2426,7 +2440,8 @@ TreeTransform::TransformDependentSizedArrayType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformDependentSizedExtVectorType( TypeLocBuilder &TLB, - DependentSizedExtVectorTypeLoc TL) { + DependentSizedExtVectorTypeLoc TL, + QualType ObjectType) { DependentSizedExtVectorType *T = TL.getTypePtr(); // FIXME: ext vector locs should be nested @@ -2468,7 +2483,8 @@ QualType TreeTransform::TransformDependentSizedExtVectorType( template QualType TreeTransform::TransformVectorType(TypeLocBuilder &TLB, - VectorTypeLoc TL) { + VectorTypeLoc TL, + QualType ObjectType) { VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) @@ -2491,7 +2507,8 @@ QualType TreeTransform::TransformVectorType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformExtVectorType(TypeLocBuilder &TLB, - ExtVectorTypeLoc TL) { + ExtVectorTypeLoc TL, + QualType ObjectType) { VectorType *T = TL.getTypePtr(); QualType ElementType = getDerived().TransformType(T->getElementType()); if (ElementType.isNull()) @@ -2516,7 +2533,8 @@ QualType TreeTransform::TransformExtVectorType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL) { + FunctionProtoTypeLoc TL, + QualType ObjectType) { FunctionProtoType *T = TL.getTypePtr(); QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) @@ -2592,7 +2610,8 @@ TreeTransform::TransformFunctionProtoType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformFunctionNoProtoType( TypeLocBuilder &TLB, - FunctionNoProtoTypeLoc TL) { + FunctionNoProtoTypeLoc TL, + QualType ObjectType) { FunctionNoProtoType *T = TL.getTypePtr(); QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc()); if (ResultType.isNull()) @@ -2612,7 +2631,8 @@ QualType TreeTransform::TransformFunctionNoProtoType( template QualType TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, - UnresolvedUsingTypeLoc TL) { + UnresolvedUsingTypeLoc TL, + QualType ObjectType) { UnresolvedUsingType *T = TL.getTypePtr(); Decl *D = getDerived().TransformDecl(T->getDecl()); if (!D) @@ -2635,7 +2655,8 @@ TreeTransform::TransformUnresolvedUsingType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, - TypedefTypeLoc TL) { + TypedefTypeLoc TL, + QualType ObjectType) { TypedefType *T = TL.getTypePtr(); TypedefDecl *Typedef = cast_or_null(getDerived().TransformDecl(T->getDecl())); @@ -2658,7 +2679,8 @@ QualType TreeTransform::TransformTypedefType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, - TypeOfExprTypeLoc TL) { + TypeOfExprTypeLoc TL, + QualType ObjectType) { // typeof expressions are not potentially evaluated contexts EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated); @@ -2685,7 +2707,8 @@ QualType TreeTransform::TransformTypeOfExprType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTypeOfType(TypeLocBuilder &TLB, - TypeOfTypeLoc TL) { + TypeOfTypeLoc TL, + QualType ObjectType) { TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo(); TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI); if (!New_Under_TI) @@ -2709,7 +2732,8 @@ QualType TreeTransform::TransformTypeOfType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformDecltypeType(TypeLocBuilder &TLB, - DecltypeTypeLoc TL) { + DecltypeTypeLoc TL, + QualType ObjectType) { DecltypeType *T = TL.getTypePtr(); // decltype expressions are not potentially evaluated contexts @@ -2736,7 +2760,8 @@ QualType TreeTransform::TransformDecltypeType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformRecordType(TypeLocBuilder &TLB, - RecordTypeLoc TL) { + RecordTypeLoc TL, + QualType ObjectType) { RecordType *T = TL.getTypePtr(); RecordDecl *Record = cast_or_null(getDerived().TransformDecl(T->getDecl())); @@ -2759,7 +2784,8 @@ QualType TreeTransform::TransformRecordType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformEnumType(TypeLocBuilder &TLB, - EnumTypeLoc TL) { + EnumTypeLoc TL, + QualType ObjectType) { EnumType *T = TL.getTypePtr(); EnumDecl *Enum = cast_or_null(getDerived().TransformDecl(T->getDecl())); @@ -2782,7 +2808,8 @@ QualType TreeTransform::TransformEnumType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformElaboratedType(TypeLocBuilder &TLB, - ElaboratedTypeLoc TL) { + ElaboratedTypeLoc TL, + QualType ObjectType) { ElaboratedType *T = TL.getTypePtr(); // FIXME: this should be a nested type. @@ -2808,25 +2835,19 @@ QualType TreeTransform::TransformElaboratedType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTemplateTypeParmType( TypeLocBuilder &TLB, - TemplateTypeParmTypeLoc TL) { + TemplateTypeParmTypeLoc TL, + QualType ObjectType) { return TransformTypeSpecType(TLB, TL); } template QualType TreeTransform::TransformSubstTemplateTypeParmType( TypeLocBuilder &TLB, - SubstTemplateTypeParmTypeLoc TL) { + SubstTemplateTypeParmTypeLoc TL, + QualType ObjectType) { return TransformTypeSpecType(TLB, TL); } -template -inline QualType -TreeTransform::TransformTemplateSpecializationType( - TypeLocBuilder &TLB, - TemplateSpecializationTypeLoc TL) { - return TransformTemplateSpecializationType(TLB, TL, QualType()); -} - template QualType TreeTransform::TransformTemplateSpecializationType( const TemplateSpecializationType *TST, @@ -2901,11 +2922,13 @@ QualType TreeTransform::TransformTemplateSpecializationType( template QualType TreeTransform::TransformQualifiedNameType(TypeLocBuilder &TLB, - QualifiedNameTypeLoc TL) { + QualifiedNameTypeLoc TL, + QualType ObjectType) { QualifiedNameType *T = TL.getTypePtr(); NestedNameSpecifier *NNS = getDerived().TransformNestedNameSpecifier(T->getQualifier(), - SourceRange()); + SourceRange(), + ObjectType); if (!NNS) return QualType(); @@ -2930,14 +2953,16 @@ TreeTransform::TransformQualifiedNameType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformTypenameType(TypeLocBuilder &TLB, - TypenameTypeLoc TL) { + TypenameTypeLoc TL, + QualType ObjectType) { TypenameType *T = TL.getTypePtr(); /* FIXME: preserve source information better than this */ SourceRange SR(TL.getNameLoc()); NestedNameSpecifier *NNS - = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR); + = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR, + ObjectType); if (!NNS) return QualType(); @@ -2970,7 +2995,8 @@ QualType TreeTransform::TransformTypenameType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformObjCInterfaceType(TypeLocBuilder &TLB, - ObjCInterfaceTypeLoc TL) { + ObjCInterfaceTypeLoc TL, + QualType ObjectType) { assert(false && "TransformObjCInterfaceType unimplemented"); return QualType(); } @@ -2978,7 +3004,8 @@ TreeTransform::TransformObjCInterfaceType(TypeLocBuilder &TLB, template QualType TreeTransform::TransformObjCObjectPointerType(TypeLocBuilder &TLB, - ObjCObjectPointerTypeLoc TL) { + ObjCObjectPointerTypeLoc TL, + QualType ObjectType) { assert(false && "TransformObjCObjectPointerType unimplemented"); return QualType(); } diff --git a/test/SemaCXX/destructor.cpp b/test/SemaCXX/destructor.cpp index 6837cd4015..a0c2c1e037 100644 --- a/test/SemaCXX/destructor.cpp +++ b/test/SemaCXX/destructor.cpp @@ -40,9 +40,9 @@ struct F { ~F(); // expected-error {{destructor cannot be redeclared}} }; -~; // expected-error {{expected the class name after '~' to name a destructor}} +~; // expected-error {{expected a class name after '~' to name a destructor}} ~undef(); // expected-error {{expected the class name after '~' to name a destructor}} -~operator+(int, int); // expected-error {{expected the class name after '~' to name a destructor}} +~operator+(int, int); // expected-error {{expected a class name after '~' to name a destructor}} ~F(){} // expected-error {{destructor must be a non-static member function}} struct G { diff --git a/test/SemaCXX/invalid-member-expr.cpp b/test/SemaCXX/invalid-member-expr.cpp index 666595c84f..7b17afbf81 100644 --- a/test/SemaCXX/invalid-member-expr.cpp +++ b/test/SemaCXX/invalid-member-expr.cpp @@ -6,7 +6,7 @@ void test() { X x; x.int; // expected-error{{expected unqualified-id}} - x.~int(); // expected-error{{expected the class name}} + x.~int(); // expected-error{{expected a class name}} x.operator; // expected-error{{missing type specifier after 'operator'}} x.operator typedef; // expected-error{{missing type specifier after 'operator'}} } @@ -15,7 +15,7 @@ void test2() { X *x; x->int; // expected-error{{expected unqualified-id}} - x->~int(); // expected-error{{expected the class name}} + x->~int(); // expected-error{{expected a class name}} x->operator; // expected-error{{missing type specifier after 'operator'}} x->operator typedef; // expected-error{{missing type specifier after 'operator'}} } diff --git a/test/SemaCXX/pseudo-destructors.cpp b/test/SemaCXX/pseudo-destructors.cpp index 15e37c5882..13ffe1b200 100644 --- a/test/SemaCXX/pseudo-destructors.cpp +++ b/test/SemaCXX/pseudo-destructors.cpp @@ -18,8 +18,8 @@ void f(A* a, Foo *f, int *i) { a->~foo(); // expected-error{{identifier 'foo' in pseudo-destructor expression does not name a type}} - // FIXME: the type printed below isn't wonderful - a->~Bar(); // expected-error{{no member named}} + // FIXME: the diagnostic below isn't wonderful + a->~Bar(); // expected-error{{does not name a type}} f->~Bar(); f->~Foo(); @@ -28,7 +28,7 @@ void f(A* a, Foo *f, int *i) { g().~Bar(); // expected-error{{non-scalar}} f->::~Bar(); - f->N::~Wibble(); + f->N::~Wibble(); // expected-error{{expected the class name after '~' to name a destructor}} f->::~Bar(17, 42); // expected-error{{cannot have any arguments}} } diff --git a/test/SemaTemplate/destructor-template.cpp b/test/SemaTemplate/destructor-template.cpp index b5ad967d69..7dd429b796 100644 --- a/test/SemaTemplate/destructor-template.cpp +++ b/test/SemaTemplate/destructor-template.cpp @@ -17,3 +17,16 @@ void destroy_me(T me) { } template void destroy_me(Incomplete*); + +namespace PR6152 { + template struct X { void f(); }; + template struct Y { }; + template + void X::f() { + Y *y; + y->template Y::~Y(); + } + + template struct X; +} + -- 2.40.0