[cfe-commits] r97058 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td include/clang/Parse/Action.h lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaExprCXX.cpp test/SemaCXX/pseudo-destructors.cpp

Douglas Gregor dgregor at apple.com
Wed Feb 24 13:29:12 PST 2010


Author: dgregor
Date: Wed Feb 24 15:29:12 2010
New Revision: 97058

URL: http://llvm.org/viewvc/llvm-project?rev=97058&view=rev
Log:
ActOnPseudoDestructorExpr now performs all semantic analysis for
pseudo-destructor expressions, and builds the CXXPseudoDestructorExpr
node directly. Currently, this only affects pseudo-destructor
expressions when they are parsed, but not after template
instantiation. That's coming next...

Improve parsing of pseudo-destructor-names. When parsing the
nested-name-specifier and we hit the sequence of tokens X :: ~, query
the actual module to determine whether X is a type-name (in which case
the X :: is part of the pseudo-destructor-name but not the
nested-name-specifier) or not (in which case the X :: is part of the
nested-name-specifier). 

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/test/SemaCXX/pseudo-destructors.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Feb 24 15:29:12 2010
@@ -2078,7 +2078,12 @@
 def err_dtor_expr_without_call : Error<
   "%select{destructor reference|pseudo-destructor expression}0 must be "
   "called immediately with '()'">;
-
+def err_pseudo_dtor_destructor_non_type : Error<
+  "%0 does not refer to a type name in pseudo-destructor expression; expected "
+  "the name of type %1">;
+def err_pseudo_dtor_template : Error<
+  "specialization of template %0 does not refer to a scalar type in pseudo-"
+  "destructor expression">;
 def err_invalid_use_of_function_type : Error<
   "a function type is not allowed here">;
 def err_invalid_use_of_array_type : Error<"an array type is not allowed here">;

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 24 15:29:12 2010
@@ -327,13 +327,26 @@
     return false;
   }
   
+  /// \brief Determine whether the given name refers to a non-type nested name
+  /// specifier, e.g., the name of a namespace or namespace alias.
+  ///
+  /// This actual is used in the parsing of pseudo-destructor names to 
+  /// distinguish a nested-name-specifier and a "type-name ::" when we
+  /// see the token sequence "X :: ~".
+  virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+                                            SourceLocation IdLoc,
+                                            IdentifierInfo &II,
+                                            TypeTy *ObjectType) {
+    return false;
+  }
+  
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').
   virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
                                                    SourceLocation CCLoc) {
     return 0;
   }
-
+  
   /// \brief Parsed an identifier followed by '::' in a C++
   /// nested-name-specifier.
   ///

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 15:29:12 2010
@@ -240,7 +240,9 @@
     // 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) {
-      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
+      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
+          !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(),
+                                                II, ObjectType)) {
         *MayBePseudoDestructor = true;
         return HasScopeSpecifier;
       }
@@ -261,7 +263,9 @@
     }
     
     if (Next.is(tok::coloncolon)) {
-      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
+      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde) &&
+          !Actions.isNonTypeNestedNameSpecifier(CurScope, SS, Tok.getLocation(),
+                                                II, ObjectType)) {
         *MayBePseudoDestructor = true;
         return HasScopeSpecifier;
       }

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 15:29:12 2010
@@ -2178,6 +2178,20 @@
                                                         TypeTy *&ObjectType,
                                                    bool &MayBePseudoDestructor);
 
+  OwningExprResult DiagnoseDtorReference(SourceLocation NameLoc,
+                                         ExprArg MemExpr);
+  
+  OwningExprResult ActOnDependentPseudoDestructorExpr(Scope *S, 
+                                                      ExprArg Base,
+                                                      SourceLocation OpLoc,
+                                                      tok::TokenKind OpKind,
+                                                      const CXXScopeSpec &SS,
+                                                  UnqualifiedId &FirstTypeName,
+                                                      SourceLocation CCLoc,
+                                                      SourceLocation TildeLoc,
+                                                  UnqualifiedId &SecondTypeName,
+                                                      bool HasTrailingLParen);
+  
   virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
                                                      SourceLocation OpLoc,
                                                      tok::TokenKind OpKind,
@@ -2187,7 +2201,7 @@
                                                      SourceLocation TildeLoc,
                                                   UnqualifiedId &SecondTypeName,
                                                      bool HasTrailingLParen);
-
+   
   /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
   /// non-empty, will create a new CXXExprWithTemporaries expression.
   /// Otherwise, just returs the passed in expression.
@@ -2215,7 +2229,11 @@
                                        bool MayBePseudoDestructor = false);
   NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
 
-
+  virtual bool isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+                                            SourceLocation IdLoc,
+                                            IdentifierInfo &II,
+                                            TypeTy *ObjectType);
+  
   CXXScopeTy *BuildCXXNestedNameSpecifier(Scope *S,
                                           const CXXScopeSpec &SS,
                                           SourceLocation IdLoc,

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Wed Feb 24 15:29:12 2010
@@ -332,6 +332,54 @@
   return 0;
 }
 
+bool Sema::isNonTypeNestedNameSpecifier(Scope *S, const CXXScopeSpec &SS,
+                                        SourceLocation IdLoc,
+                                        IdentifierInfo &II,
+                                        TypeTy *ObjectTypePtr) {
+  QualType ObjectType = GetTypeFromParser(ObjectTypePtr);
+  LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName);
+  
+  // Determine where to perform name lookup
+  DeclContext *LookupCtx = 0;
+  bool isDependent = false;
+  if (!ObjectType.isNull()) {
+    // This nested-name-specifier occurs in a member access expression, e.g.,
+    // x->B::f, and we are looking into the type of the object.
+    assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist");
+    LookupCtx = computeDeclContext(ObjectType);
+    isDependent = ObjectType->isDependentType();
+  } else if (SS.isSet()) {
+    // This nested-name-specifier occurs after another nested-name-specifier,
+    // so long into the context associated with the prior nested-name-specifier.
+    LookupCtx = computeDeclContext(SS, false);
+    isDependent = isDependentScopeSpecifier(SS);
+    Found.setContextRange(SS.getRange());
+  }
+  
+  if (LookupCtx) {
+    // Perform "qualified" name lookup into the declaration context we
+    // computed, which is either the type of the base of a member access
+    // expression or the declaration context associated with a prior
+    // nested-name-specifier.
+    
+    // The declaration context must be complete.
+    if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(SS))
+      return false;
+    
+    LookupQualifiedName(Found, LookupCtx);
+  } else if (isDependent) {
+    return false;
+  } else {
+    LookupName(Found, S);
+  }
+  Found.suppressDiagnostics();
+  
+  if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
+    return isa<NamespaceDecl>(ND) || isa<NamespaceAliasDecl>(ND);
+  
+  return false;
+}
+
 /// \brief Build a new nested-name-specifier for "identifier::", as described
 /// by ActOnCXXNestedNameSpecifier.
 ///

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Wed Feb 24 15:29:12 2010
@@ -3178,23 +3178,6 @@
   return ExprError();
 }
 
-static Sema::OwningExprResult DiagnoseDtorReference(Sema &SemaRef,
-                                                    SourceLocation NameLoc,
-                                                    Sema::ExprArg MemExpr) {
-  Expr *E = (Expr *) MemExpr.get();
-  SourceLocation ExpectedLParenLoc = SemaRef.PP.getLocForEndOfToken(NameLoc);
-  SemaRef.Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
-    << isa<CXXPseudoDestructorExpr>(E)
-    << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
-  
-  return SemaRef.ActOnCallExpr(/*Scope*/ 0,
-                               move(MemExpr),
-                               /*LPLoc*/ ExpectedLParenLoc,
-                               Sema::MultiExprArg(SemaRef, 0, 0),
-                               /*CommaLocs*/ 0,
-                               /*RPLoc*/ ExpectedLParenLoc);
-}
-
 /// The main callback when the parser finds something like
 ///   expression . [nested-name-specifier] identifier
 ///   expression -> [nested-name-specifier] identifier
@@ -3265,7 +3248,7 @@
         // call now.
         if (!HasTrailingLParen &&
             Id.getKind() == UnqualifiedId::IK_DestructorName)
-          return DiagnoseDtorReference(*this, NameLoc, move(Result));
+          return DiagnoseDtorReference(NameLoc, move(Result));
 
         return move(Result);
       }

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 15:29:12 2010
@@ -2410,31 +2410,41 @@
   return move(Base);
 }
 
-Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
-                                                       SourceLocation OpLoc,
-                                                       tok::TokenKind OpKind,
-                                                       const CXXScopeSpec &SS,
-                                                  UnqualifiedId &FirstTypeName,
-                                                       SourceLocation CCLoc,
-                                                       SourceLocation TildeLoc,
-                                                 UnqualifiedId &SecondTypeName,
-                                                       bool HasTrailingLParen) {
-  assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
-          FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
-         "Invalid first type name in pseudo-destructor");
-  assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
-          SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
-         "Invalid second type name in pseudo-destructor");
+Sema::OwningExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc,
+                                                   ExprArg MemExpr) {
+  Expr *E = (Expr *) MemExpr.get();
+  SourceLocation ExpectedLParenLoc = PP.getLocForEndOfToken(NameLoc);
+  Diag(E->getLocStart(), diag::err_dtor_expr_without_call)
+    << isa<CXXPseudoDestructorExpr>(E)
+    << CodeModificationHint::CreateInsertion(ExpectedLParenLoc, "()");
+  
+  return ActOnCallExpr(/*Scope*/ 0,
+                       move(MemExpr),
+                       /*LPLoc*/ ExpectedLParenLoc,
+                       Sema::MultiExprArg(*this, 0, 0),
+                       /*CommaLocs*/ 0,
+                       /*RPLoc*/ ExpectedLParenLoc);
+}
 
+Sema::OwningExprResult 
+Sema::ActOnDependentPseudoDestructorExpr(Scope *S, 
+                                         ExprArg Base,
+                                         SourceLocation OpLoc,
+                                         tok::TokenKind OpKind,
+                                         const CXXScopeSpec &SS,
+                                         UnqualifiedId &FirstTypeName,
+                                         SourceLocation CCLoc,
+                                         SourceLocation TildeLoc,
+                                         UnqualifiedId &SecondTypeName,
+                                         bool HasTrailingLParen) {
   Expr *BaseE = (Expr *)Base.get();
-  QualType ObjectType;
-  if (BaseE->isTypeDependent())
-    ObjectType = Context.DependentTy;
-
+  QualType ObjectType = BaseE->getType();
+  assert(ObjectType->isDependentType());
+  
   // The nested-name-specifier provided by the parser, then extended
   // by the "type-name ::" in the pseudo-destructor-name, if present.
   CXXScopeSpec ExtendedSS = SS;
-
+  
   if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || 
       FirstTypeName.Identifier) {
     // We have a pseudo-destructor with a "type-name ::". 
@@ -2443,13 +2453,13 @@
     if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
       // Resolve the identifier to a nested-name-specifier.
       CXXScopeTy *FinalScope
-        = ActOnCXXNestedNameSpecifier(S, SS, 
-                                      FirstTypeName.StartLocation,
-                                      CCLoc,
-                                      *FirstTypeName.Identifier,
-                                      true,
-                                      ObjectType.getAsOpaquePtr(),
-                                      false);
+      = ActOnCXXNestedNameSpecifier(S, SS, 
+                                    FirstTypeName.StartLocation,
+                                    CCLoc,
+                                    *FirstTypeName.Identifier,
+                                    true,
+                                    ObjectType.getAsOpaquePtr(),
+                                    false);
       if (SS.getBeginLoc().isInvalid())
         ExtendedSS.setBeginLoc(FirstTypeName.StartLocation);
       ExtendedSS.setEndLoc(CCLoc);
@@ -2468,11 +2478,11 @@
                                          TemplateId->RAngleLoc);
       if (!T.isInvalid()) {
         CXXScopeTy *FinalScope
-          = ActOnCXXNestedNameSpecifier(S, SS, T.get(), 
-                                        SourceRange(TemplateId->TemplateNameLoc,
-                                                    TemplateId->RAngleLoc),
-                                        CCLoc,
-                                        true);
+        = ActOnCXXNestedNameSpecifier(S, SS, T.get(), 
+                                      SourceRange(TemplateId->TemplateNameLoc,
+                                                  TemplateId->RAngleLoc),
+                                      CCLoc,
+                                      true);
         if (SS.getBeginLoc().isInvalid())
           ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc);
         ExtendedSS.setEndLoc(CCLoc);
@@ -2480,7 +2490,7 @@
       }
     }
   }
-
+  
   // Produce a destructor name based on the second type-name (which
   // follows the tilde).
   TypeTy *DestructedType;
@@ -2490,7 +2500,7 @@
     bool isDependent = isDependentScopeSpecifier(ExtendedSS);
     if (isDependent || computeDeclContext(ExtendedSS))
       LookupSS = &ExtendedSS;
-
+    
     DestructedType = getTypeName(*SecondTypeName.Identifier, 
                                  SecondTypeName.StartLocation,
                                  S, LookupSS, true, ObjectType.getTypePtr());
@@ -2514,13 +2524,13 @@
       if (!DestructedType)
         return ExprError();
     }
-
+    
     if (!DestructedType) {
       // FIXME: Crummy diagnostic.
       Diag(SecondTypeName.StartLocation, diag::err_destructor_class_name);
       return ExprError();
     }
-
+    
     EndLoc = SecondTypeName.EndLocation;
   } else {
     // Resolve the template-id to a type, and that to a
@@ -2528,7 +2538,7 @@
     TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
     ASTTemplateArgsPtr TemplateArgsPtr(*this,
                                        TemplateId->getTemplateArgs(),
-                                         TemplateId->NumArgs);
+                                       TemplateId->NumArgs);
     EndLoc = TemplateId->RAngleLoc;
     TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
                                        TemplateId->TemplateNameLoc,
@@ -2540,7 +2550,7 @@
     
     DestructedType = T.get();
   }
-
+  
   // Form a (possibly fake) destructor name and let the member access
   // expression code deal with this.
   // FIXME: Don't do this! It's totally broken!
@@ -2548,6 +2558,169 @@
   Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc);
   return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS, 
                                Destructor, DeclPtrTy(), HasTrailingLParen);
+  
+}
+
+Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
+                                                       SourceLocation OpLoc,
+                                                       tok::TokenKind OpKind,
+                                                       const CXXScopeSpec &SS,
+                                                  UnqualifiedId &FirstTypeName,
+                                                       SourceLocation CCLoc,
+                                                       SourceLocation TildeLoc,
+                                                 UnqualifiedId &SecondTypeName,
+                                                       bool HasTrailingLParen) {
+  assert((FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+          FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
+         "Invalid first type name in pseudo-destructor");
+  assert((SecondTypeName.getKind() == UnqualifiedId::IK_TemplateId ||
+          SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) &&
+         "Invalid second type name in pseudo-destructor");
+
+  Expr *BaseE = (Expr *)Base.get();
+  if (BaseE->isTypeDependent())
+    return ActOnDependentPseudoDestructorExpr(S, move(Base), OpLoc, OpKind,
+                                              SS, FirstTypeName, CCLoc, 
+                                              TildeLoc, SecondTypeName,
+                                              HasTrailingLParen);
+  
+  // C++ [expr.pseudo]p2:
+  //   The left-hand side of the dot operator shall be of scalar type. The 
+  //   left-hand side of the arrow operator shall be of pointer to scalar type.
+  //   This scalar type is the object type. 
+  QualType ObjectType = BaseE->getType();
+  if (OpKind == tok::arrow) {
+    if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
+      ObjectType = Ptr->getPointeeType();
+    } else {
+      // The user wrote "p->" when she probably meant "p."; fix it.
+      Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
+        << ObjectType << true
+        << CodeModificationHint::CreateReplacement(OpLoc, ".");
+      if (isSFINAEContext())
+        return ExprError();
+      
+      OpKind = tok::period;
+    }
+  }
+
+  if (!ObjectType->isScalarType()) {
+    Diag(OpLoc, diag::err_pseudo_dtor_base_not_scalar)
+      << ObjectType << BaseE->getSourceRange();
+    return ExprError();
+  }
+
+  // 
+  
+  // C++ [expr.pseudo]p2:
+  //   [...] The cv-unqualified versions of the object type and of the type 
+  //   designated by the pseudo-destructor-name shall be the same type.
+  QualType DestructedType;
+  TypeSourceInfo *DestructedTypeInfo = 0;
+  if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
+    TypeTy *T = getTypeName(*SecondTypeName.Identifier, 
+                            SecondTypeName.StartLocation,
+                            S, &SS);
+    if (!T) {
+      Diag(SecondTypeName.StartLocation, 
+           diag::err_pseudo_dtor_destructor_non_type)
+        << SecondTypeName.Identifier << ObjectType;
+      if (isSFINAEContext())
+        return ExprError();
+      
+      // Recover by assuming we had the right type all along.
+      DestructedType = ObjectType;
+    } else {
+      DestructedType = GetTypeFromParser(T, &DestructedTypeInfo);
+      
+      if (!DestructedType->isDependentType() &&
+          !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+        // The types mismatch. Recover by assuming we had the right type
+        // all along.
+        Diag(SecondTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch)
+          << ObjectType << DestructedType << BaseE->getSourceRange();
+        
+        DestructedType = ObjectType;
+        DestructedTypeInfo = 0;
+      }
+    }
+  } else {
+    // FIXME: C++0x template aliases would allow a template-id here. For now,
+    // just diagnose this as an error.
+    TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
+    Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template)
+      << TemplateId->Name << ObjectType
+      << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc);
+    if (isSFINAEContext())
+      return ExprError();
+    
+    // Recover by assuming we had the right type all along.
+    DestructedType = ObjectType;
+  }
+  
+  // C++ [expr.pseudo]p2:
+  //   [...] Furthermore, the two type-names in a pseudo-destructor-name of the
+  //   form
+  //
+  //     ::[opt] nested-name-specifier[opt] type-name :: ~ type-name 
+  //
+  //   shall designate the same scalar type.  
+  QualType ScopeType;
+  if (FirstTypeName.getKind() == UnqualifiedId::IK_TemplateId || 
+      FirstTypeName.Identifier) {
+    if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
+      TypeTy *T = getTypeName(*FirstTypeName.Identifier, 
+                              FirstTypeName.StartLocation,
+                              S, &SS);
+      if (!T) {
+        Diag(FirstTypeName.StartLocation, 
+             diag::err_pseudo_dtor_destructor_non_type)
+          << FirstTypeName.Identifier << ObjectType;
+        if (isSFINAEContext())
+          return ExprError();        
+      } else {
+        // FIXME: Drops source-location information.
+        ScopeType = GetTypeFromParser(T);
+        
+        if (!ScopeType->isDependentType() &&
+            !Context.hasSameUnqualifiedType(DestructedType, ScopeType)) {
+          // The types mismatch. Recover by assuming we don't have a scoping 
+          // type.
+          Diag(FirstTypeName.StartLocation, diag::err_pseudo_dtor_type_mismatch)
+            << ObjectType << ScopeType << BaseE->getSourceRange();
+          
+          ScopeType = QualType();
+        }
+      }
+    } else {
+      // FIXME: C++0x template aliases would allow a template-id here. For now,
+      // just diagnose this as an error.
+      TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
+      Diag(TemplateId->TemplateNameLoc, diag::err_pseudo_dtor_template)
+        << TemplateId->Name << ObjectType
+        << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc);
+      if (isSFINAEContext())
+        return ExprError();
+      
+      // Recover by assuming we have no scoping type.
+      DestructedType = ObjectType;
+    }
+  }
+  
+  // FIXME: Drops the scope type.
+  OwningExprResult Result
+    = Owned(new (Context) CXXPseudoDestructorExpr(Context, 
+                                                  Base.takeAs<Expr>(),
+                                                  OpKind == tok::arrow,
+                                                  OpLoc,
+                                       (NestedNameSpecifier *) SS.getScopeRep(),
+                                                  SS.getRange(),
+                                                  DestructedType,
+                                                 SecondTypeName.StartLocation));
+  if (HasTrailingLParen)
+    return move(Result);
+  
+  return DiagnoseDtorReference(SecondTypeName.StartLocation, move(Result));
 }
 
 CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, 

Modified: cfe/trunk/test/SemaCXX/pseudo-destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/pseudo-destructors.cpp?rev=97058&r1=97057&r2=97058&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/pseudo-destructors.cpp (original)
+++ cfe/trunk/test/SemaCXX/pseudo-destructors.cpp Wed Feb 24 15:29:12 2010
@@ -11,6 +11,7 @@
 
 namespace N {
   typedef Foo Wibble;
+  typedef int OtherInteger;
 }
 
 void f(A* a, Foo *f, int *i, double *d) {
@@ -35,8 +36,11 @@
 
   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}}
+  i->N::~OtherInteger();
+  i->N::OtherInteger::~OtherInteger();
+  i->N::OtherInteger::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
+  i->N::~Integer(); // expected-error{{'Integer' does not refer to a type name in pseudo-destructor expression; expected the name of type 'int'}}
+  i->Integer::~Double(); // expected-error{{the type of object expression ('int') does not match the type being destroyed ('Double' (aka 'double')) in pseudo-destructor expression}}
 }
 
 typedef int Integer;





More information about the cfe-commits mailing list