From: Douglas Gregor Date: Mon, 19 Oct 2009 22:04:39 +0000 (+0000) Subject: Parse a simple-template-id following a '~' when calling a destructor, e.g., X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=dd62b15665a4144c45c1f7c53665414ad5f7f4f2;p=clang Parse a simple-template-id following a '~' when calling a destructor, e.g., t->~T() Fixes PR5213. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84545 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 1ee14701fa..cefd512aee 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1390,6 +1390,34 @@ public: return ExprEmpty(); } + /// \brief Parsed a C++ destructor reference that refers to a type. + /// + /// This action is used when parsing a destructor reference that uses a + /// template-id, e.g., + /// + /// \code + /// t->~Tmpl + /// \endcode + /// + /// \param S the scope in which the destructor reference occurs. + /// \param Base the base object of the destructor reference expression. + /// \param OpLoc the location of the operator ('.' or '->'). + /// \param OpKind the kind of the destructor reference operator ('.' or '->'). + /// \param TypeRange the source range that covers the destructor type. + /// \param Type the type that is being destroyed. + /// \param SS the scope specifier that precedes the destructor name. + /// \param HasTrailingLParen whether the destructor name is followed by a '('. + virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *Type, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + return ExprEmpty(); + } + /// ActOnOverloadedOperatorReferenceExpr - Parsed an overloaded operator /// reference, for example: /// diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 72e30e3b60..8be89a8916 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -972,13 +972,41 @@ Parser::ParsePostfixExpressionSuffix(OwningExprResult LHS) { return ExprError(); } - if (!LHS.isInvalid()) - LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), - OpLoc, OpKind, - Tok.getLocation(), - Tok.getIdentifierInfo(), - SS, - NextToken().is(tok::l_paren)); + if (NextToken().is(tok::less)) { + // class-name: + // ~ simple-template-id + TemplateTy Template + = Actions.ActOnDependentTemplateName(SourceLocation(), + *Tok.getIdentifierInfo(), + Tok.getLocation(), + SS, + ObjectType); + if (AnnotateTemplateIdToken(Template, TNK_Type_template, &SS, + SourceLocation(), true)) + return ExprError(); + + assert(Tok.is(tok::annot_typename) && + "AnnotateTemplateIdToken didn't work?"); + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getAnnotationRange(), + Tok.getAnnotationValue(), + SS, + NextToken().is(tok::l_paren)); + } else { + // class-name: + // ~ identifier + if (!LHS.isInvalid()) + LHS = Actions.ActOnDestructorReferenceExpr(CurScope, move(LHS), + OpLoc, OpKind, + Tok.getLocation(), + Tok.getIdentifierInfo(), + SS, + NextToken().is(tok::l_paren)); + } + + // Consume the identifier or template-id token. ConsumeToken(); } else if (getLang().CPlusPlus && Tok.is(tok::kw_operator)) { // We have a reference to a member operator, e.g., t.operator int or diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 1cadcecd88..208100e594 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2107,6 +2107,15 @@ public: const CXXScopeSpec &SS, bool HasTrailingLParen); + virtual OwningExprResult + ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *Type, + const CXXScopeSpec &SS, + bool HasTrailingLParen); + virtual OwningExprResult ActOnOverloadedOperatorReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index ebb5b519c1..dfffb3008c 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2099,6 +2099,8 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, ClassName); else { TypeTy *BaseTy = getTypeName(*ClassName, ClassNameLoc, S, &SS); + + // FIXME: If Base is dependent, we might not be able to resolve it here. if (!BaseTy) { Diag(ClassNameLoc, diag::err_ident_in_pseudo_dtor_not_a_type) << ClassName; @@ -2108,25 +2110,41 @@ Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, BaseType = GetTypeFromParser(BaseTy); } - CanQualType CanBaseType = Context.getCanonicalType(BaseType); - DeclarationName DtorName = - Context.DeclarationNames.getCXXDestructorName(CanBaseType); + return ActOnDestructorReferenceExpr(S, move(Base), OpLoc, OpKind, + SourceRange(ClassNameLoc), + BaseType.getAsOpaquePtr(), + SS, HasTrailingLParen); +} +Sema::OwningExprResult +Sema::ActOnDestructorReferenceExpr(Scope *S, ExprArg Base, + SourceLocation OpLoc, + tok::TokenKind OpKind, + SourceRange TypeRange, + TypeTy *T, + const CXXScopeSpec &SS, + bool HasTrailingLParen) { + QualType Type = QualType::getFromOpaquePtr(T); + CanQualType CanType = Context.getCanonicalType(Type); + DeclarationName DtorName = + Context.DeclarationNames.getCXXDestructorName(CanType); + OwningExprResult Result - = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, ClassNameLoc, - DtorName, DeclPtrTy(), &SS); + = BuildMemberReferenceExpr(S, move(Base), OpLoc, OpKind, + TypeRange.getBegin(), DtorName, DeclPtrTy(), + &SS); if (Result.isInvalid() || HasTrailingLParen) return move(Result); - + // The only way a reference to a destructor can be used is to // immediately call them. Since the next token is not a '(', produce a // diagnostic and build the call now. Expr *E = (Expr *)Result.get(); - SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(E->getLocEnd()); + SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(TypeRange.getEnd()); Diag(E->getLocStart(), diag::err_dtor_expr_without_call) << isa(E) << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()"); - + return ActOnCallExpr(0, move(Result), ExpectedLParenLoc, MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc); } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 00af8c1ca0..7360b8fc7a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -253,7 +253,8 @@ public: /// Identifiers and selectors are returned unmodified. Sublcasses may /// override this function to provide alternate behavior. DeclarationName TransformDeclarationName(DeclarationName Name, - SourceLocation Loc); + SourceLocation Loc, + QualType ObjectType = QualType()); /// \brief Transform the given template name. /// @@ -276,6 +277,10 @@ public: QualType Transform##CLASS##Type(const CLASS##Type *T); #include "clang/AST/TypeNodes.def" + QualType + TransformTemplateSpecializationType(const TemplateSpecializationType *T, + QualType ObjectType); + OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr); #define STMT(Node, Parent) \ @@ -1734,7 +1739,8 @@ TreeTransform::TransformNestedNameSpecifier(NestedNameSpecifier *NNS, template DeclarationName TreeTransform::TransformDeclarationName(DeclarationName Name, - SourceLocation Loc) { + SourceLocation Loc, + QualType ObjectType) { if (!Name) return Name; @@ -1751,7 +1757,14 @@ TreeTransform::TransformDeclarationName(DeclarationName Name, case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: { TemporaryBase Rebase(*this, Loc, Name); - QualType T = getDerived().TransformType(Name.getCXXNameType()); + QualType T; + if (!ObjectType.isNull() && + isa(Name.getCXXNameType())) { + TemplateSpecializationType *SpecType + = cast(Name.getCXXNameType()); + T = TransformTemplateSpecializationType(SpecType, ObjectType); + } else + T = getDerived().TransformType(Name.getCXXNameType()); if (T.isNull()) return DeclarationName(); @@ -1814,7 +1827,8 @@ TreeTransform::TransformTemplateName(TemplateName Name, return TemplateName(); if (!getDerived().AlwaysRebuild() && - NNS == DTN->getQualifier()) + NNS == DTN->getQualifier() && + ObjectType.isNull()) return Name; return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType); @@ -2335,11 +2349,19 @@ QualType TreeTransform::TransformSubstTemplateTypeParmType( return QualType(T, 0); } +template +inline QualType +TreeTransform::TransformTemplateSpecializationType( + const TemplateSpecializationType *T) { + return TransformTemplateSpecializationType(T, QualType()); +} + template QualType TreeTransform::TransformTemplateSpecializationType( - const TemplateSpecializationType *T) { + const TemplateSpecializationType *T, + QualType ObjectType) { TemplateName Template - = getDerived().TransformTemplateName(T->getTemplateName()); + = getDerived().TransformTemplateName(T->getTemplateName(), ObjectType); if (Template.isNull()) return QualType(); @@ -4186,7 +4208,7 @@ TreeTransform::TransformCXXUnresolvedMemberExpr( // refer to a built-in type!). NamedDecl *FirstQualifierInScope = cast_or_null( - getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); + getDerived().TransformDecl(E->getFirstQualifierFoundInScope())); NestedNameSpecifier *Qualifier = 0; if (E->getQualifier()) { @@ -4199,7 +4221,8 @@ TreeTransform::TransformCXXUnresolvedMemberExpr( } DeclarationName Name - = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc()); + = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(), + QualType::getFromOpaquePtr(ObjectType)); if (!Name) return SemaRef.ExprError(); diff --git a/test/SemaTemplate/member-template-access-expr.cpp b/test/SemaTemplate/member-template-access-expr.cpp index 20437aee39..9f227c05e1 100644 --- a/test/SemaTemplate/member-template-access-expr.cpp +++ b/test/SemaTemplate/member-template-access-expr.cpp @@ -28,3 +28,26 @@ void test_f1(XDerived xd) { // int &ir = f1(xd); } +// PR5213 +template +struct A {}; + +template +class B +{ + A a_; + +public: + void destroy(); +}; + +template +void +B::destroy() +{ + a_.~A(); +} + +void do_destroy_B(B b) { + b.destroy(); +}