Implement support for parsing pseudo-destructor expression with a nested-name-specifier, e.g.,

  typedef int Int;
  int *p;
  p->Int::~Int();

This weakens the invariant that the only types in nested-name-specifiers are tag types (restricted to class types in C++98/03). However, we weaken this invariant as little as possible, accepting arbitrary types in nested-name-specifiers only when we're in a member access expression that looks like a pseudo-destructor expression.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96743 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 932d6eb..a8fbaff 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -45,10 +45,14 @@
 /// \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
+/// 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 EnteringContext,
+                                            bool InMemberAccessExpr) {
   assert(getLang().CPlusPlus &&
          "Call sites of this function should be guarded by checking for C++");
 
@@ -169,7 +173,8 @@
       // 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 (TemplateId->Kind == TNK_Type_template ||
           TemplateId->Kind == TNK_Dependent_template_name) {
         AnnotateTemplateIdTokenAsType(&SS);
@@ -191,7 +196,8 @@
             Actions.ActOnCXXNestedNameSpecifier(CurScope, SS,
                                                 TypeToken.getAnnotationValue(),
                                                 TypeToken.getAnnotationRange(),
-                                                CCLoc));
+                                                CCLoc,
+                                                MayBePseudoDestructor));
         else
           SS.setScopeRep(0);
         SS.setEndLoc(CCLoc);
@@ -217,18 +223,23 @@
     
     // 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 &&
-        Actions.IsInvalidUnlessNestedName(CurScope, SS, II, 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
-        // recover like this.
-        PP.LookAhead(1).is(tok::identifier)) {
-      Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
-        << CodeModificationHint::CreateReplacement(Next.getLocation(), "::");
+    if (Next.is(tok::colon) && !ColonIsSacred) {
+      bool MayBePseudoDestructor
+        = InMemberAccessExpr && GetLookAheadToken(2).is(tok::tilde);
       
-      // Recover as if the user wrote '::'.
-      Next.setKind(tok::coloncolon);
+      if (Actions.IsInvalidUnlessNestedName(CurScope, SS, II, 
+                                            MayBePseudoDestructor, 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
+          // recover like this.
+          PP.LookAhead(1).is(tok::identifier)) {
+        Diag(Next, diag::err_unexected_colon_in_nested_name_spec)
+          << CodeModificationHint::CreateReplacement(Next.getLocation(), "::");
+        
+        // Recover as if the user wrote '::'.
+        Next.setKind(tok::coloncolon);
+      }
     }
     
     if (Next.is(tok::coloncolon)) {
@@ -247,9 +258,12 @@
       if (SS.isInvalid())
         continue;
 
+      bool MayBePseudoDestructor = InMemberAccessExpr && Tok.is(tok::tilde);
+
       SS.setScopeRep(
         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, II,
-                                            ObjectType, EnteringContext));
+                                            MayBePseudoDestructor, ObjectType,
+                                            EnteringContext));
       SS.setEndLoc(CCLoc);
       continue;
     }