]> granicus.if.org Git - clang/commitdiff
Parse a simple-template-id following a '~' when calling a destructor, e.g.,
authorDouglas Gregor <dgregor@apple.com>
Mon, 19 Oct 2009 22:04:39 +0000 (22:04 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 19 Oct 2009 22:04:39 +0000 (22:04 +0000)
  t->~T<A0, A1>()

Fixes PR5213.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84545 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Parse/Action.h
lib/Parse/ParseExpr.cpp
lib/Sema/Sema.h
lib/Sema/SemaExprCXX.cpp
lib/Sema/TreeTransform.h
test/SemaTemplate/member-template-access-expr.cpp

index 1ee14701fa2d7870704243e39090485937fa31a6..cefd512aee0a6fc9447e5aa2e89b8de37a055ac4 100644 (file)
@@ -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<T1, T2>
+  /// \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:
   ///
index 72e30e3b607967a6f6a5e029a301741ea56c0e1c..8be89a8916800d6673bc28f65959b6a0fbb6b753 100644 (file)
@@ -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
index 1cadcecd8818f530d0ebada2a5c5d0a11833f134..208100e59427f46271bbdff074dfc42bd740e6bb 100644 (file)
@@ -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,
index ebb5b519c1a5c3d96eaab197afe4980c2c49a257..dfffb3008c8f5b3b499677e883c9f64f86249579 100644 (file)
@@ -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<CXXPseudoDestructorExpr>(E)
     << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
-
+  
   return ActOnCallExpr(0, move(Result), ExpectedLParenLoc,
                        MultiExprArg(*this, 0, 0), 0, ExpectedLParenLoc);
 }
index 00af8c1ca0e50bbcb0987602abf77a96b9364d82..7360b8fc7a86028e96d3c6da4ff25079169a27fd 100644 (file)
@@ -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<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
 template<typename Derived>
 DeclarationName
 TreeTransform<Derived>::TransformDeclarationName(DeclarationName Name,
-                                                 SourceLocation Loc) {
+                                                 SourceLocation Loc,
+                                                 QualType ObjectType) {
   if (!Name)
     return Name;
 
@@ -1751,7 +1757,14 @@ TreeTransform<Derived>::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<TemplateSpecializationType>(Name.getCXXNameType())) {
+      TemplateSpecializationType *SpecType
+        = cast<TemplateSpecializationType>(Name.getCXXNameType());
+      T = TransformTemplateSpecializationType(SpecType, ObjectType);
+    } else
+      T = getDerived().TransformType(Name.getCXXNameType());
     if (T.isNull())
       return DeclarationName();
 
@@ -1814,7 +1827,8 @@ TreeTransform<Derived>::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<Derived>::TransformSubstTemplateTypeParmType(
   return QualType(T, 0);
 }
 
+template<typename Derived>
+inline QualType 
+TreeTransform<Derived>::TransformTemplateSpecializationType(
+                                          const TemplateSpecializationType *T) {
+  return TransformTemplateSpecializationType(T, QualType());
+}
+  
 template<typename Derived>
 QualType TreeTransform<Derived>::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<Derived>::TransformCXXUnresolvedMemberExpr(
   // refer to a built-in type!).
   NamedDecl *FirstQualifierInScope
     = cast_or_null<NamedDecl>(
-              getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
+               getDerived().TransformDecl(E->getFirstQualifierFoundInScope()));
 
   NestedNameSpecifier *Qualifier = 0;
   if (E->getQualifier()) {
@@ -4199,7 +4221,8 @@ TreeTransform<Derived>::TransformCXXUnresolvedMemberExpr(
   }
 
   DeclarationName Name
-    = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc());
+    = getDerived().TransformDeclarationName(E->getMember(), E->getMemberLoc(),
+                                       QualType::getFromOpaquePtr(ObjectType));
   if (!Name)
     return SemaRef.ExprError();
 
index 20437aee39dc3881581b2b083b3a6b38ff960d2e..9f227c05e1d4566fbf23bb56cbbc6f20a2125b25 100644 (file)
@@ -28,3 +28,26 @@ void test_f1(XDerived xd) {
 //  int &ir = f1<X>(xd);
 }
 
+// PR5213
+template <class T>
+struct A {};
+
+template<class T>
+class B
+{
+  A<T> a_;
+  
+public:
+  void destroy();
+};
+
+template<class T>
+void
+B<T>::destroy()
+{
+  a_.~A<T>();
+}
+
+void do_destroy_B(B<int> b) {
+  b.destroy();
+}