Use CXXPseudoDestructorExpr as the stored representation for dependent
expressions that look like pseudo-destructors, e.g.,

  p->T::~T()

where p has dependent type.

At template instantiate time, we determine whether we actually have a
pseudo-destructor or a member access, and funnel down to the
appropriate routine in Sema.

Fixes PR6380.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97092 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index abc775e..1bc084c 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -95,6 +95,7 @@
   class ObjCMethodDecl;
   class ObjCPropertyDecl;
   class ObjCContainerDecl;
+  class PseudoDestructorTypeStorage;
   class FunctionProtoType;
   class CXXBasePath;
   class CXXBasePaths;
@@ -2188,20 +2189,9 @@
                                              TypeSourceInfo *ScopeType,
                                              SourceLocation CCLoc,
                                              SourceLocation TildeLoc,
-                                             TypeSourceInfo *DestroyedType,
+                                     PseudoDestructorTypeStorage DestroyedType,
                                              bool HasTrailingLParen);
-  
-  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,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 025f2ad..64f2ef2 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -161,7 +161,7 @@
     Found.clear();
     if (Step == 0 && LookupCtx)
       LookupQualifiedName(Found, LookupCtx);
-    else if (Step == 1 && LookInScope)
+    else if (Step == 1 && LookInScope && S)
       LookupName(Found, S);
     else
       continue;
@@ -2441,9 +2441,9 @@
                                                  TypeSourceInfo *ScopeTypeInfo,
                                                        SourceLocation CCLoc,
                                                        SourceLocation TildeLoc,
-                                             TypeSourceInfo *DestructedTypeInfo,
+                                         PseudoDestructorTypeStorage Destructed,
                                                        bool HasTrailingLParen) {
-  assert(DestructedTypeInfo && "No destructed type in pseudo-destructor expr?");
+  TypeSourceInfo *DestructedTypeInfo = Destructed.getTypeSourceInfo();
   
   // C++ [expr.pseudo]p2:
   //   The left-hand side of the dot operator shall be of scalar type. The 
@@ -2475,21 +2475,24 @@
   // 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 = DestructedTypeInfo->getType();
-  SourceLocation DestructedTypeStart
-    = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
-  if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
-      !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
-    Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
-      << ObjectType << DestructedType << BaseE->getSourceRange()
-      << DestructedTypeInfo->getTypeLoc().getSourceRange();
-    
-    // Recover by 
-    DestructedType = ObjectType;
-    DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
-                                                         DestructedTypeStart);
+  if (DestructedTypeInfo) {
+    QualType DestructedType = DestructedTypeInfo->getType();
+    SourceLocation DestructedTypeStart
+      = DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin();
+    if (!DestructedType->isDependentType() && !ObjectType->isDependentType() &&
+        !Context.hasSameUnqualifiedType(DestructedType, ObjectType)) {
+      Diag(DestructedTypeStart, diag::err_pseudo_dtor_type_mismatch)
+        << ObjectType << DestructedType << BaseE->getSourceRange()
+        << DestructedTypeInfo->getTypeLoc().getSourceRange();
+      
+      // Recover by setting the destructed type to the object type.
+      DestructedType = ObjectType;
+      DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType,
+                                                           DestructedTypeStart);
+      Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+    }
   }
-   
+  
   // C++ [expr.pseudo]p2:
   //   [...] Furthermore, the two type-names in a pseudo-destructor-name of the
   //   form
@@ -2522,148 +2525,12 @@
                                                   ScopeTypeInfo,
                                                   CCLoc,
                                                   TildeLoc,
-                                                  DestructedTypeInfo));
+                                                  Destructed));
+            
   if (HasTrailingLParen)
     return move(Result);
   
-  return DiagnoseDtorReference(
-                  DestructedTypeInfo->getTypeLoc().getSourceRange().getBegin(),
-                               move(Result));  
-}
-
-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 = 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 ::". 
-    // FIXME: As a temporary hack, we go ahead and resolve this to part of
-    // a nested-name-specifier.
-    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);
-      if (SS.getBeginLoc().isInvalid())
-        ExtendedSS.setBeginLoc(FirstTypeName.StartLocation);
-      ExtendedSS.setEndLoc(CCLoc);
-      ExtendedSS.setScopeRep(FinalScope);
-    } else {
-      // Resolve the template-id to a type, and that to a
-      // nested-name-specifier.
-      TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId;
-      ASTTemplateArgsPtr TemplateArgsPtr(*this,
-                                         TemplateId->getTemplateArgs(),
-                                         TemplateId->NumArgs);
-      TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
-                                         TemplateId->TemplateNameLoc,
-                                         TemplateId->LAngleLoc,
-                                         TemplateArgsPtr,
-                                         TemplateId->RAngleLoc);
-      if (!T.isInvalid()) {
-        CXXScopeTy *FinalScope
-        = ActOnCXXNestedNameSpecifier(S, SS, T.get(), 
-                                      SourceRange(TemplateId->TemplateNameLoc,
-                                                  TemplateId->RAngleLoc),
-                                      CCLoc,
-                                      true);
-        if (SS.getBeginLoc().isInvalid())
-          ExtendedSS.setBeginLoc(TemplateId->TemplateNameLoc);
-        ExtendedSS.setEndLoc(CCLoc);
-        ExtendedSS.setScopeRep(FinalScope);        
-      }
-    }
-  }
-  
-  // Produce a destructor name based on the second type-name (which
-  // follows the tilde).
-  TypeTy *DestructedType;
-  SourceLocation EndLoc;
-  if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
-    const CXXScopeSpec *LookupSS = &SS;
-    bool isDependent = isDependentScopeSpecifier(ExtendedSS);
-    if (isDependent || computeDeclContext(ExtendedSS))
-      LookupSS = &ExtendedSS;
-    
-    DestructedType = getTypeName(*SecondTypeName.Identifier, 
-                                 SecondTypeName.StartLocation,
-                                 S, LookupSS, true, ObjectType.getTypePtr());
-    if (!DestructedType && isDependent) {
-      // We didn't find our type, but that's okay: it's dependent
-      // anyway.
-      // FIXME: We should not be building a typename type here!
-      NestedNameSpecifier *NNS = 0;
-      SourceRange Range;
-      if (SS.isSet()) {
-        NNS = (NestedNameSpecifier *)ExtendedSS.getScopeRep();
-        Range = SourceRange(ExtendedSS.getRange().getBegin(), 
-                            SecondTypeName.StartLocation);
-      } else {
-        NNS = NestedNameSpecifier::Create(Context, SecondTypeName.Identifier);
-        Range = SourceRange(SecondTypeName.StartLocation);
-      }
-      
-      DestructedType = CheckTypenameType(NNS, *SecondTypeName.Identifier, 
-                                         Range).getAsOpaquePtr();
-      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
-    // nested-name-specifier.
-    TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId;
-    ASTTemplateArgsPtr TemplateArgsPtr(*this,
-                                       TemplateId->getTemplateArgs(),
-                                       TemplateId->NumArgs);
-    EndLoc = TemplateId->RAngleLoc;
-    TypeResult T = ActOnTemplateIdType(TemplateTy::make(TemplateId->Template),
-                                       TemplateId->TemplateNameLoc,
-                                       TemplateId->LAngleLoc,
-                                       TemplateArgsPtr,
-                                       TemplateId->RAngleLoc);
-    if (T.isInvalid() || !T.get())
-      return ExprError();
-    
-    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!
-  UnqualifiedId Destructor;
-  Destructor.setDestructorName(TildeLoc, DestructedType, EndLoc);
-  return ActOnMemberAccessExpr(S, move(Base), OpLoc, OpKind, ExtendedSS, 
-                               Destructor, DeclPtrTy(), HasTrailingLParen);
-  
+  return DiagnoseDtorReference(Destructed.getLocation(), move(Result));
 }
 
 Sema::OwningExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
@@ -2683,11 +2550,6 @@
          "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 
@@ -2697,27 +2559,46 @@
   if (OpKind == tok::arrow) {
     if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
       ObjectType = Ptr->getPointeeType();
-    } else if (!BaseE->isTypeDependent()) {
+    } else if (!ObjectType->isDependentType()) {
       // The user wrote "p->" when she probably meant "p."; fix it.
       Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
-      << ObjectType << true
-      << CodeModificationHint::CreateReplacement(OpLoc, ".");
+        << ObjectType << true
+        << CodeModificationHint::CreateReplacement(OpLoc, ".");
       if (isSFINAEContext())
         return ExprError();
       
       OpKind = tok::period;
     }
   }
+
+  // Compute the object type that we should use for name lookup purposes. Only
+  // record types and dependent types matter.
+  void *ObjectTypePtrForLookup = 0;
+  if (!SS.isSet()) {
+    ObjectTypePtrForLookup = (void *)ObjectType->getAs<RecordType>();
+    if (!ObjectTypePtrForLookup && ObjectType->isDependentType())
+      ObjectTypePtrForLookup = Context.DependentTy.getAsOpaquePtr();
+  }
   
   // Convert the name of the type being destructed (following the ~) into a 
   // type (with source-location information).
   QualType DestructedType;
   TypeSourceInfo *DestructedTypeInfo = 0;
+  PseudoDestructorTypeStorage Destructed;
   if (SecondTypeName.getKind() == UnqualifiedId::IK_Identifier) {
     TypeTy *T = getTypeName(*SecondTypeName.Identifier, 
                             SecondTypeName.StartLocation,
-                            S, &SS);
-    if (!T) {
+                            S, &SS, true, ObjectTypePtrForLookup);
+    if (!T && 
+        ((SS.isSet() && !computeDeclContext(SS, false)) ||
+         (!SS.isSet() && ObjectType->isDependentType()))) {
+      // The name of the type being destroyed is a dependent name, and we 
+      // couldn't find anything useful in scope. Just store the identifier and
+      // it's location, and we'll perform (qualified) name lookup again at
+      // template instantiation time.
+      Destructed = PseudoDestructorTypeStorage(SecondTypeName.Identifier,
+                                               SecondTypeName.StartLocation);
+    } else if (!T) {
       Diag(SecondTypeName.StartLocation, 
            diag::err_pseudo_dtor_destructor_non_type)
         << SecondTypeName.Identifier << ObjectType;
@@ -2748,9 +2629,12 @@
   
   // If we've performed some kind of recovery, (re-)build the type source 
   // information.
-  if (!DestructedTypeInfo)
-    DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType,
+  if (!DestructedType.isNull()) {
+    if (!DestructedTypeInfo)
+      DestructedTypeInfo = Context.getTrivialTypeSourceInfo(DestructedType,
                                                   SecondTypeName.StartLocation);
+    Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo);
+  }
   
   // Convert the name of the scope type (the type prior to '::') into a type.
   TypeSourceInfo *ScopeTypeInfo = 0;
@@ -2760,7 +2644,7 @@
     if (FirstTypeName.getKind() == UnqualifiedId::IK_Identifier) {
       TypeTy *T = getTypeName(*FirstTypeName.Identifier, 
                               FirstTypeName.StartLocation,
-                              S, &SS);
+                              S, &SS, false, ObjectTypePtrForLookup);
       if (!T) {
         Diag(FirstTypeName.StartLocation, 
              diag::err_pseudo_dtor_destructor_non_type)
@@ -2799,7 +2683,7 @@
     
   return BuildPseudoDestructorExpr(move(Base), OpLoc, OpKind, SS,
                                    ScopeTypeInfo, CCLoc, TildeLoc,
-                                   DestructedTypeInfo, HasTrailingLParen);
+                                   Destructed, HasTrailingLParen);
 }
 
 CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, 
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 922c041..416f480 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -884,12 +884,12 @@
   OwningExprResult RebuildCXXPseudoDestructorExpr(ExprArg Base,
                                                   SourceLocation OperatorLoc,
                                                   bool isArrow,
-                                                  NestedNameSpecifier *Qualifier,
+                                                NestedNameSpecifier *Qualifier,
                                                   SourceRange QualifierRange,
                                                   TypeSourceInfo *ScopeType,
                                                   SourceLocation CCLoc,
                                                   SourceLocation TildeLoc,
-                                                TypeSourceInfo *DestroyedType);
+                                        PseudoDestructorTypeStorage Destroyed);
 
   /// \brief Build a new unary operator expression.
   ///
@@ -4671,34 +4671,67 @@
   if (Base.isInvalid())
     return SemaRef.ExprError();
 
+  Sema::TypeTy *ObjectTypePtr = 0;
+  bool MayBePseudoDestructor = false;
+  Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base), 
+                                              E->getOperatorLoc(),
+                                        E->isArrow()? tok::arrow : tok::period,
+                                              ObjectTypePtr,
+                                              MayBePseudoDestructor);
+  if (Base.isInvalid())
+    return SemaRef.ExprError();
+                                              
+  QualType ObjectType = QualType::getFromOpaquePtr(ObjectTypePtr);
   NestedNameSpecifier *Qualifier
     = getDerived().TransformNestedNameSpecifier(E->getQualifier(),
                                                 E->getQualifierRange(),
-                                                true);
+                                                true,
+                                                ObjectType);
   if (E->getQualifier() && !Qualifier)
     return SemaRef.ExprError();
 
-  // FIXME: Object type!
-  TypeSourceInfo *DestroyedTypeInfo
-    = getDerived().TransformType(E->getDestroyedTypeInfo());
-  if (!DestroyedTypeInfo)
-    return SemaRef.ExprError();
+  PseudoDestructorTypeStorage Destroyed;
+  if (E->getDestroyedTypeInfo()) {
+    TypeSourceInfo *DestroyedTypeInfo
+      = getDerived().TransformType(E->getDestroyedTypeInfo(), ObjectType);
+    if (!DestroyedTypeInfo)
+      return SemaRef.ExprError();
+    Destroyed = DestroyedTypeInfo;
+  } else if (ObjectType->isDependentType()) {
+    // We aren't likely to be able to resolve the identifier down to a type
+    // now anyway, so just retain the identifier.
+    Destroyed = PseudoDestructorTypeStorage(E->getDestroyedTypeIdentifier(),
+                                            E->getDestroyedTypeLoc());
+  } else {
+    // Look for a destructor known with the given name.
+    CXXScopeSpec SS;
+    if (Qualifier) {
+      SS.setScopeRep(Qualifier);
+      SS.setRange(E->getQualifierRange());
+    }
+    
+    Sema::TypeTy *T = SemaRef.getDestructorName(E->getTildeLoc(),
+                                              *E->getDestroyedTypeIdentifier(),
+                                                E->getDestroyedTypeLoc(),
+                                                /*Scope=*/0,
+                                                SS, ObjectTypePtr,
+                                                false);
+    if (!T)
+      return SemaRef.ExprError();
+    
+    Destroyed
+      = SemaRef.Context.getTrivialTypeSourceInfo(SemaRef.GetTypeFromParser(T),
+                                                 E->getDestroyedTypeLoc());
+  }
 
-  // FIXME: Object type!
   TypeSourceInfo *ScopeTypeInfo = 0;
   if (E->getScopeTypeInfo()) {
-    ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo());
+    ScopeTypeInfo = getDerived().TransformType(E->getScopeTypeInfo(), 
+                                               ObjectType);
     if (!ScopeTypeInfo)
       return SemaRef.ExprError();
   }
   
-  if (!getDerived().AlwaysRebuild() &&
-      Base.get() == E->getBase() &&
-      Qualifier == E->getQualifier() &&
-      ScopeTypeInfo == E->getScopeTypeInfo() &&
-      DestroyedTypeInfo == E->getDestroyedTypeInfo())
-    return SemaRef.Owned(E->Retain());
-
   return getDerived().RebuildCXXPseudoDestructorExpr(move(Base),
                                                      E->getOperatorLoc(),
                                                      E->isArrow(),
@@ -4707,7 +4740,7 @@
                                                      ScopeTypeInfo,
                                                      E->getColonColonLoc(),
                                                      E->getTildeLoc(),
-                                                     DestroyedTypeInfo);
+                                                     Destroyed);
 }
 
 template<typename Derived>
@@ -5758,7 +5791,7 @@
                                                      TypeSourceInfo *ScopeType,
                                                        SourceLocation CCLoc,
                                                        SourceLocation TildeLoc,
-                                               TypeSourceInfo *DestroyedType) {
+                                        PseudoDestructorTypeStorage Destroyed) {
   CXXScopeSpec SS;
   if (Qualifier) {
     SS.setRange(QualifierRange);
@@ -5767,18 +5800,19 @@
 
   Expr *BaseE = (Expr *)Base.get();
   QualType BaseType = BaseE->getType();
-  if (BaseE->isTypeDependent() ||
+  if (BaseE->isTypeDependent() || Destroyed.getIdentifier() ||
       (!isArrow && !BaseType->getAs<RecordType>()) ||
       (isArrow && BaseType->getAs<PointerType>() && 
-       !BaseType->getAs<PointerType>()->getAs<RecordType>())) {
+       !BaseType->getAs<PointerType>()->getPointeeType()->getAs<RecordType>())){
     // This pseudo-destructor expression is still a pseudo-destructor.
     return SemaRef.BuildPseudoDestructorExpr(move(Base), OperatorLoc,
                                              isArrow? tok::arrow : tok::period,
                                              SS, ScopeType, CCLoc, TildeLoc,
-                                             DestroyedType, 
+                                             Destroyed,
                                              /*FIXME?*/true);
   }
   
+  TypeSourceInfo *DestroyedType = Destroyed.getTypeSourceInfo();
   DeclarationName Name
     = SemaRef.Context.DeclarationNames.getCXXDestructorName(
                 SemaRef.Context.getCanonicalType(DestroyedType->getType()));
@@ -5788,8 +5822,7 @@
   return getSema().BuildMemberReferenceExpr(move(Base), BaseType,
                                             OperatorLoc, isArrow,
                                             SS, /*FIXME: FirstQualifier*/ 0,
-                                            Name, 
-                        DestroyedType->getTypeLoc().getSourceRange().getBegin(),
+                                            Name, Destroyed.getLocation(),
                                             /*TemplateArgs*/ 0);
 }