[cfe-commits] r97045 - in /cfe/trunk: include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/TreeTransform.h

Douglas Gregor dgregor at apple.com
Wed Feb 24 10:44:31 PST 2010


Author: dgregor
Date: Wed Feb 24 12:44:31 2010
New Revision: 97045

URL: http://llvm.org/viewvc/llvm-project?rev=97045&view=rev
Log:
Rework parsing of pseudo-destructor expressions and explicit
destructor calls, e.g., 

  p->T::~T

We now detect when the member access that we've parsed, e.g.,

  p-> or x.

may be a pseudo-destructor expression, either because the type of p or
x is a scalar or because it is dependent (and, therefore, may become a
scalar at template instantiation time). 

We then parse the pseudo-destructor grammar specifically:

  ::[opt] nested-name-specifier[opt] type-name :: ∼ type-name

and hand those results to a new action, ActOnPseudoDestructorExpr,
which will cope with both dependent member accesses of destructors and
with pseudo-destructor expressions.

This commit affects the parsing of pseudo-destructors, only; the
semantic actions still go through the semantic actions for member
access expressions. That will change soon.


Modified:
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/TreeTransform.h

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Wed Feb 24 12:44:31 2010
@@ -1614,12 +1614,66 @@
   /// with the type into which name lookup should look to find the member in
   /// the member access expression.
   ///
+  /// \param MayBePseudoDestructor Originally false. The action should
+  /// set this true if the expression may end up being a
+  /// pseudo-destructor expression, indicating to the parser that it
+  /// shoudl be parsed as a pseudo-destructor rather than as a member
+  /// access expression. Note that this should apply both when the
+  /// object type is a scalar and when the object type is dependent.
+  ///
   /// \returns the (possibly modified) \p Base expression
   virtual OwningExprResult ActOnStartCXXMemberReference(Scope *S,
                                                         ExprArg Base,
                                                         SourceLocation OpLoc,
                                                         tok::TokenKind OpKind,
-                                                        TypeTy *&ObjectType) {
+                                                        TypeTy *&ObjectType,
+                                                  bool &MayBePseudoDestructor) {
+    return ExprEmpty();
+  }
+
+  /// \brief Parsed a C++ pseudo-destructor expression or a dependent
+  /// member access expression that has the same syntactic form as a
+  /// pseudo-destructor expression.
+  ///
+  /// \param S The scope in which the member access expression occurs.
+  ///
+  /// \param Base The expression in which a member is being accessed, e.g., the
+  /// "x" in "x.f".
+  ///
+  /// \param OpLoc The location of the member access operator ("." or "->")
+  ///
+  /// \param OpKind The kind of member access operator ("." or "->")
+  ///
+  /// \param SS The nested-name-specifier that precedes the type names
+  /// in the grammar. Note that this nested-name-specifier will not
+  /// cover the last "type-name ::" in the grammar, because it isn't
+  /// necessarily a nested-name-specifier.
+  ///
+  /// \param FirstTypeName The type name that follows the optional
+  /// nested-name-specifier but precedes the '::', e.g., the first
+  /// type-name in "type-name :: type-name". This type name may be
+  /// empty. This will be either an identifier or a template-id.
+  ///
+  /// \param CCLoc The location of the '::' in "type-name ::
+  /// typename". May be invalid, if there is no \p FirstTypeName.
+  ///
+  /// \param TildeLoc The location of the '~'.
+  ///
+  /// \param SecondTypeName The type-name following the '~', which is
+  /// the name of the type being destroyed. This will be either an
+  /// identifier or a template-id.
+  ///
+  /// \param HasTrailingLParen Whether the next token in the stream is
+  /// a left parentheses.
+  virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
+                                                     SourceLocation OpLoc,
+                                                     tok::TokenKind OpKind,
+                                                     const CXXScopeSpec &SS,
+                                                  UnqualifiedId &FirstTypeName,
+                                                     SourceLocation CCLoc,
+                                                     SourceLocation TildeLoc,
+                                                 UnqualifiedId &SecondTypeName,
+                                                     bool HasTrailingLParen) {
     return ExprEmpty();
   }
 

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed Feb 24 12:44:31 2010
@@ -964,7 +964,7 @@
   bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
                                       TypeTy *ObjectType,
                                       bool EnteringContext,
-                                      bool InMemberAccessExpr = false);
+                                      bool *MayBePseudoDestructor = 0);
 
   //===--------------------------------------------------------------------===//
   // C++ 5.2p1: C++ Casts
@@ -975,6 +975,13 @@
   OwningExprResult ParseCXXTypeid();
 
   //===--------------------------------------------------------------------===//
+  // C++ 5.2.4: C++ Pseudo-Destructor Expressions
+  OwningExprResult ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
+                                            tok::TokenKind OpKind,
+                                            CXXScopeSpec &SS,
+                                            Action::TypeTy *ObjectType);
+
+  //===--------------------------------------------------------------------===//
   // C++ 9.3.2: C++ 'this' pointer
   OwningExprResult ParseCXXThis();
 
@@ -1415,7 +1422,8 @@
                                     SourceLocation NameLoc,
                                     bool EnteringContext,
                                     TypeTy *ObjectType,
-                                    UnqualifiedId &Id);
+                                    UnqualifiedId &Id,
+                                    bool AssumeTemplateId = false);
   bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
                                   TypeTy *ObjectType,
                                   UnqualifiedId &Result);

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Wed Feb 24 12:44:31 2010
@@ -996,12 +996,16 @@
 
       CXXScopeSpec SS;
       Action::TypeTy *ObjectType = 0;
+      bool MayBePseudoDestructor = false;
       if (getLang().CPlusPlus && !LHS.isInvalid()) {
         LHS = Actions.ActOnStartCXXMemberReference(CurScope, move(LHS),
-                                                   OpLoc, OpKind, ObjectType);
+                                                   OpLoc, OpKind, ObjectType,
+                                                   MayBePseudoDestructor);
         if (LHS.isInvalid())
           break;
-        ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, true);
+
+        ParseOptionalCXXScopeSpecifier(SS, ObjectType, false, 
+                                       &MayBePseudoDestructor);
       }
 
       if (Tok.is(tok::code_completion)) {
@@ -1012,6 +1016,17 @@
         ConsumeToken();
       }
       
+      if (MayBePseudoDestructor) {
+        LHS = ParseCXXPseudoDestructor(move(LHS), OpLoc, OpKind, SS, 
+                                       ObjectType);
+        break;
+      }
+
+      // Either the action has told is that this cannot be a
+      // pseudo-destructor expression (based on the type of base
+      // expression), or we didn't see a '~' in the right place. We
+      // can still parse a destructor name here, but in that case it
+      // names a real destructor.
       UnqualifiedId Name;
       if (ParseUnqualifiedId(SS, 
                              /*EnteringContext=*/false, 
@@ -1022,10 +1037,9 @@
         return ExprError();
       
       if (!LHS.isInvalid())
-        LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, OpKind,
-                                            SS, Name, ObjCImpDecl,
+        LHS = Actions.ActOnMemberAccessExpr(CurScope, move(LHS), OpLoc, 
+                                            OpKind, SS, Name, ObjCImpDecl,
                                             Tok.is(tok::l_paren));
-      
       break;
     }
     case tok::plusplus:    // postfix-expression: postfix-expression '++'

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Feb 24 12:44:31 2010
@@ -45,14 +45,21 @@
 /// \param EnteringContext whether we will be entering into the context of
 /// the nested-name-specifier after parsing it.
 ///
-/// \param InMemberAccessExpr Whether this scope specifier is within a
+/// \param MayBePseudoDestructor When non-NULL, points to a flag that
+/// indicates whether this nested-name-specifier may be part of a
+/// pseudo-destructor name. In this case, the flag will be set false
+/// if we don't actually end up parsing a destructor name. Moreorover,
+/// if we do end up determining that we are parsing a destructor name,
+/// the last component of the nested-name-specifier is not parsed as
+/// part of the scope specifier.
+
 /// member access expression, e.g., the \p T:: in \p p->T::m.
 ///
 /// \returns true if a scope specifier was parsed.
 bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
                                             Action::TypeTy *ObjectType,
                                             bool EnteringContext,
-                                            bool InMemberAccessExpr) {
+                                            bool *MayBePseudoDestructor) {
   assert(getLang().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
 
@@ -79,6 +86,12 @@
     HasScopeSpecifier = true;
   }
 
+  bool CheckForDestructor = false;
+  if (MayBePseudoDestructor && *MayBePseudoDestructor) {
+    CheckForDestructor = true;
+    *MayBePseudoDestructor = false;
+  }
+
   while (true) {
     if (HasScopeSpecifier) {
       // C++ [basic.lookup.classref]p5:
@@ -173,8 +186,11 @@
       // convert it into a type within the nested-name-specifier.
       TemplateIdAnnotation *TemplateId
         = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
-      bool MayBePseudoDestructor
-        = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde);
+      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
+        *MayBePseudoDestructor = true;
+        return HasScopeSpecifier;
+      }
+
       if (TemplateId->Kind == TNK_Type_template ||
           TemplateId->Kind == TNK_Dependent_template_name) {
         AnnotateTemplateIdTokenAsType(&SS);
@@ -197,7 +213,7 @@
                                                 TypeToken.getAnnotationValue(),
                                                 TypeToken.getAnnotationRange(),
                                                 CCLoc,
-                                                MayBePseudoDestructor));
+                                                false));
         else
           SS.setScopeRep(0);
         SS.setEndLoc(CCLoc);
@@ -224,11 +240,13 @@
     // 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) {
-      bool MayBePseudoDestructor
-        = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde);
-      
+      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
+        *MayBePseudoDestructor = true;
+        return HasScopeSpecifier;
+      }
+
       if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, 
-                                            MayBePseudoDestructor, ObjectType,
+                                            false, ObjectType,
                                             EnteringContext) &&
           // If the token after the colon isn't an identifier, it's still an
           // error, but they probably meant something else strange so don't
@@ -243,6 +261,11 @@
     }
     
     if (Next.is(tok::coloncolon)) {
+      if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) {
+        *MayBePseudoDestructor = true;
+        return HasScopeSpecifier;
+      }
+
       // We have an identifier followed by a '::'. Lookup this name
       // as the name in a nested-name-specifier.
       SourceLocation IdLoc = ConsumeToken();
@@ -258,11 +281,9 @@
       if (SS.isInvalid())
         continue;
 
-      bool MayBePseudoDestructor = InMemberAccessExpr && Tok.is(tok::tilde);
-
       SS.setScopeRep(
         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
-                                            MayBePseudoDestructor, ObjectType,
+                                            false, ObjectType,
                                             EnteringContext));
       SS.setEndLoc(CCLoc);
       continue;
@@ -298,6 +319,12 @@
     break;
   }
 
+  // Even if we didn't see any pieces of a nested-name-specifier, we
+  // still check whether there is a tilde in this position, which
+  // indicates a potential pseudo-destructor.
+  if (CheckForDestructor && Tok.is(tok::tilde))
+    *MayBePseudoDestructor = true;
+
   return HasScopeSpecifier;
 }
 
@@ -493,6 +520,77 @@
   return move(Result);
 }
 
+/// \brief Parse a C++ pseudo-destructor expression after the base,
+/// . or -> operator, and nested-name-specifier have already been
+/// parsed.
+///
+///       postfix-expression: [C++ 5.2]
+///         postfix-expression . pseudo-destructor-name
+///         postfix-expression -> pseudo-destructor-name
+///
+///       pseudo-destructor-name: 
+///         ::[opt] nested-name-specifier[opt] type-name :: ~type-name 
+///         ::[opt] nested-name-specifier template simple-template-id :: 
+///                 ~type-name 
+///         ::[opt] nested-name-specifier[opt] ~type-name
+///       
+Parser::OwningExprResult 
+Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
+                                 tok::TokenKind OpKind,
+                                 CXXScopeSpec &SS,
+                                 Action::TypeTy *ObjectType) {
+  // We're parsing either a pseudo-destructor-name or a dependent
+  // member access that has the same form as a
+  // pseudo-destructor-name. We parse both in the same way and let
+  // the action model sort them out.
+  //
+  // Note that the ::[opt] nested-name-specifier[opt] has already
+  // been parsed, and if there was a simple-template-id, it has
+  // been coalesced into a template-id annotation token.
+  UnqualifiedId FirstTypeName;
+  SourceLocation CCLoc;
+  if (Tok.is(tok::identifier)) {
+    FirstTypeName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
+    ConsumeToken();
+    assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
+    CCLoc = ConsumeToken();
+  } else if (Tok.is(tok::annot_template_id)) {
+    FirstTypeName.setTemplateId(
+                              (TemplateIdAnnotation *)Tok.getAnnotationValue());
+    ConsumeToken();
+    assert(Tok.is(tok::coloncolon) &&"ParseOptionalCXXScopeSpecifier fail");
+    CCLoc = ConsumeToken();
+  } else {
+    FirstTypeName.setIdentifier(0, SourceLocation());
+  }
+
+  // Parse the tilde.
+  assert(Tok.is(tok::tilde) && "ParseOptionalCXXScopeSpecifier fail");
+  SourceLocation TildeLoc = ConsumeToken();
+  if (!Tok.is(tok::identifier)) {
+    Diag(Tok, diag::err_destructor_tilde_identifier);
+    return ExprError();
+  }
+  
+  // Parse the second type.
+  UnqualifiedId SecondTypeName;
+  IdentifierInfo *Name = Tok.getIdentifierInfo();
+  SourceLocation NameLoc = ConsumeToken();
+  SecondTypeName.setIdentifier(Name, NameLoc);
+  
+  // If there is a '<', the second type name is a template-id. Parse
+  // it as such.
+  if (Tok.is(tok::less) &&
+      ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType,
+                                   SecondTypeName, /*AssumeTemplateName=*/true))
+    return ExprError();
+
+  return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind,
+                                           SS, FirstTypeName, CCLoc,
+                                           TildeLoc, SecondTypeName,
+                                           Tok.is(tok::l_paren));
+}
+
 /// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
 ///
 ///       boolean-literal: [C++ 2.13.5]
@@ -818,13 +916,17 @@
 /// that precedes the '<'. If template arguments were parsed successfully,
 /// will be updated with the template-id.
 /// 
+/// \param AssumeTemplateId When true, this routine will assume that the name
+/// refers to a template without performing name lookup to verify. 
+///
 /// \returns true if a parse error occurred, false otherwise.
 bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
                                           IdentifierInfo *Name,
                                           SourceLocation NameLoc,
                                           bool EnteringContext,
                                           TypeTy *ObjectType,
-                                          UnqualifiedId &Id) {
+                                          UnqualifiedId &Id,
+                                          bool AssumeTemplateId) {
   assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
   
   TemplateTy Template;
@@ -833,8 +935,16 @@
   case UnqualifiedId::IK_Identifier:
   case UnqualifiedId::IK_OperatorFunctionId:
   case UnqualifiedId::IK_LiteralOperatorId:
-    TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, EnteringContext, 
-                                 Template);
+    if (AssumeTemplateId) {
+      Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, 
+                                                    Id, ObjectType,
+                                                    EnteringContext);
+      TNK = TNK_Dependent_template_name;
+      if (!Template.get())
+        return true;      
+    } else 
+      TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, 
+                                   EnteringContext, Template);
     break;
       
   case UnqualifiedId::IK_ConstructorName: {

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Feb 24 12:44:31 2010
@@ -2175,7 +2175,18 @@
                                                         ExprArg Base,
                                                         SourceLocation OpLoc,
                                                         tok::TokenKind OpKind,
-                                                        TypeTy *&ObjectType);
+                                                        TypeTy *&ObjectType,
+                                                   bool &MayBePseudoDestructor);
+
+  virtual OwningExprResult ActOnPseudoDestructorExpr(Scope *S, ExprArg Base,
+                                                     SourceLocation OpLoc,
+                                                     tok::TokenKind OpKind,
+                                                     const CXXScopeSpec &SS,
+                                                   UnqualifiedId &FirstTypeName,
+                                                     SourceLocation CCLoc,
+                                                     SourceLocation TildeLoc,
+                                                  UnqualifiedId &SecondTypeName,
+                                                     bool HasTrailingLParen);
 
   /// MaybeCreateCXXExprWithTemporaries - If the list of temporaries is
   /// non-empty, will create a new CXXExprWithTemporaries expression.

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Feb 24 12:44:31 2010
@@ -21,6 +21,7 @@
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/Template.h"
 #include "llvm/ADT/STLExtras.h"
 using namespace clang;
 
@@ -2325,7 +2326,8 @@
 
 Sema::OwningExprResult
 Sema::ActOnStartCXXMemberReference(Scope *S, ExprArg Base, SourceLocation OpLoc,
-                                   tok::TokenKind OpKind, TypeTy *&ObjectType) {
+                                   tok::TokenKind OpKind, TypeTy *&ObjectType,
+                                   bool &MayBePseudoDestructor) {
   // Since this might be a postfix expression, get rid of ParenListExprs.
   Base = MaybeConvertParenListExprToParenExpr(S, move(Base));
 
@@ -2333,6 +2335,7 @@
   assert(BaseExpr && "no record expansion");
 
   QualType BaseType = BaseExpr->getType();
+  MayBePseudoDestructor = false;
   if (BaseType->isDependentType()) {
     // If we have a pointer to a dependent type and are using the -> operator,
     // the object type is the type that the pointer points to. We might still
@@ -2342,6 +2345,7 @@
         BaseType = Ptr->getPointeeType();
     
     ObjectType = BaseType.getAsOpaquePtr();
+    MayBePseudoDestructor = true;
     return move(Base);
   }
 
@@ -2383,7 +2387,11 @@
     //   [...] If the type of the object expression is of pointer to scalar
     //   type, the unqualified-id is looked up in the context of the complete
     //   postfix-expression.
+    //
+    // This also indicates that we should be parsing a
+    // pseudo-destructor-name.
     ObjectType = 0;
+    MayBePseudoDestructor = true;
     return move(Base);
   }
 
@@ -2399,10 +2407,149 @@
   //   type C (or of pointer to a class type C), the unqualified-id is looked
   //   up in the scope of class C. [...]
   ObjectType = BaseType.getAsOpaquePtr();
-  
   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");
+
+  Expr *BaseE = (Expr *)Base.get();
+  QualType ObjectType;
+  if (BaseE->isTypeDependent())
+    ObjectType = Context.DependentTy;
+
+  // 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);
+}
+
 CXXMemberCallExpr *Sema::BuildCXXMemberCallExpr(Expr *Exp, 
                                                 CXXMethodDecl *Method) {
   if (PerformObjectArgumentInitialization(Exp, Method))

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=97045&r1=97044&r2=97045&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Wed Feb 24 12:44:31 2010
@@ -5041,10 +5041,12 @@
 
     // Start the member reference and compute the object's type.
     Sema::TypeTy *ObjectTy = 0;
+    bool MayBePseudoDestructor = false;
     Base = SemaRef.ActOnStartCXXMemberReference(0, move(Base),
                                                 E->getOperatorLoc(),
                                       E->isArrow()? tok::arrow : tok::period,
-                                                ObjectTy);
+                                                ObjectTy,
+                                                MayBePseudoDestructor);
     if (Base.isInvalid())
       return SemaRef.ExprError();
 





More information about the cfe-commits mailing list