http://reviews.llvm.org/D6389

Files:
  include/clang/Basic/DiagnosticParseKinds.td
  include/clang/Sema/Sema.h
  lib/Parse/ParseExprCXX.cpp
  lib/Sema/SemaCXXScopeSpec.cpp
  test/SemaCXX/nested-name-spec.cpp
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -539,6 +539,10 @@
   "unexpected %0 in function call; perhaps remove the %0?">;
 def err_super_in_using_declaration : Error<
   "'__super' cannot be used with a using declaration">;
+def err_nested_name_spec_is_enum : Error<
+  "unscoped enumeration name shall not be specified in nested name specifier">;
+def err_expected_class_or_namespace_or_enum : Error<"%0 is not a class"
+  "%select{ or namespace|, namespace, or scoped enumeration}1">;
 
 // C++ derived classes
 def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -4610,6 +4610,23 @@
                                     IdentifierInfo &II,
                                     ParsedType ObjectType);
 
+  /// \brief Collects information that may be used to recover erroneous nested
+  /// name specifier.
+  struct NameSpecRecoveryInfo {
+    bool CorrectToColon; //> suggestions to replace '::' -> ':' are allowed
+    bool CorrectionToColonRequested; //> Replacement '::' -> ':' recovers error
+    TypeDecl *FoundDecl; //> Declaration if found for name spec
+
+    NameSpecRecoveryInfo(bool CorrectColon) {
+      clear();
+      CorrectToColon = CorrectColon;
+    }
+    void clear() {
+      CorrectToColon = CorrectionToColonRequested = false;
+      FoundDecl = nullptr;
+    }
+  };
+
   bool BuildCXXNestedNameSpecifier(Scope *S,
                                    IdentifierInfo &Identifier,
                                    SourceLocation IdentifierLoc,
@@ -4619,7 +4636,7 @@
                                    CXXScopeSpec &SS,
                                    NamedDecl *ScopeLookupResult,
                                    bool ErrorRecoveryLookup,
-                                   bool *IsCorrectedToColon = nullptr);
+                                   NameSpecRecoveryInfo *RecovInfo = nullptr);
 
   /// \brief The parser has parsed a nested-name-specifier 'identifier::'.
   ///
@@ -4645,9 +4662,8 @@
   /// \param ErrorRecoveryLookup If true, then this method is called to improve
   /// error recovery. In this case do not emit error message.
   ///
-  /// \param IsCorrectedToColon If not null, suggestions to replace '::' -> ':'
-  /// are allowed.  The bool value pointed by this parameter is set to 'true'
-  /// if the identifier is treated as if it was followed by ':', not '::'.
+  /// \param RecovInfo If not null, points to a structure that is contains info
+  /// for error recovery.
   ///
   /// \returns true if an error occurred, false otherwise.
   bool ActOnCXXNestedNameSpecifier(Scope *S,
@@ -4658,7 +4674,7 @@
                                    bool EnteringContext,
                                    CXXScopeSpec &SS,
                                    bool ErrorRecoveryLookup = false,
-                                   bool *IsCorrectedToColon = nullptr);
+                                   NameSpecRecoveryInfo *RecovInfo = nullptr);
 
   ExprResult ActOnDecltypeExpression(Expr *E);
 
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp
+++ lib/Parse/ParseExprCXX.cpp
@@ -472,20 +472,47 @@
 
       CheckForLParenAfterColonColon();
 
-      bool IsCorrectedToColon = false;
-      bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
+      Sema::NameSpecRecoveryInfo RecovInfo(ColonIsSacred);
       if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc,
                                               ObjectType, EnteringContext, SS,
-                                              false, CorrectionFlagPtr)) {
+                                              false, &RecovInfo)) {
         // Identifier is not recognized as a nested name, but we can have
         // mistyped '::' instead of ':'.
-        if (CorrectionFlagPtr && IsCorrectedToColon) {
+        if (RecovInfo.CorrectToColon && RecovInfo.CorrectionToColonRequested) {
           ColonColon.setKind(tok::colon);
           PP.EnterToken(Tok);
           PP.EnterToken(ColonColon);
           Tok = Identifier;
           break;
         }
+        if (RecovInfo.FoundDecl) {
+          // The current identifier does not represents entity that may be used
+          // as nested name spec, it nevertheless resolves to a declaration. See
+          // if we can do error recover here.
+          bool ErrorReported = false;
+          if (EnumDecl *ED = dyn_cast<EnumDecl>(RecovInfo.FoundDecl)) {
+            // Maybe non scoped enum is used as scoped?  If so this identifier
+            // must be followed by another, which is corresponding enumerator.
+            if (!ED->isScoped() && Tok.is(tok::identifier) &&
+                NextToken().isNot(tok::coloncolon)) {
+              IdentifierInfo *Id = Tok.getIdentifierInfo();
+              for (auto Enumerator : ED->enumerators()) {
+                if (Enumerator->getName().equals(Id->getName())) {
+                  // We can recover parsing by throwing away enumeration name.
+                  Diag(IdLoc, diag::err_nested_name_spec_is_enum) <<
+                      FixItHint::CreateRemoval(SourceRange(IdLoc, CCLoc));
+                  ErrorReported = true;
+                  break;
+                }
+              }
+            }
+          }
+          if (!ErrorReported) {
+            Diag(IdLoc, diag::err_expected_class_or_namespace_or_enum)
+              << QualType(RecovInfo.FoundDecl->getTypeForDecl(), 0)
+              << getLangOpts().CPlusPlus;
+          }
+        }
         SS.SetInvalid(SourceRange(IdLoc, CCLoc));
       }
       HasScopeSpecifier = true;
Index: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp
+++ lib/Sema/SemaCXXScopeSpec.cpp
@@ -427,10 +427,8 @@
 ///        definition time.
 /// \param ErrorRecoveryLookup Specifies if the method is called to improve
 ///        error recovery and what kind of recovery is performed.
-/// \param IsCorrectedToColon If not null, suggestion of replace '::' -> ':'
-///        are allowed.  The bool value pointed by this parameter is set to
-///       'true' if the identifier is treated as if it was followed by ':',
-///        not '::'.
+/// \param RecovInfo If not null, points to a structure that contains info
+///        for error recovery.
 ///
 /// This routine differs only slightly from ActOnCXXNestedNameSpecifier, in
 /// that it contains an extra parameter \p ScopeLookupResult, which provides
@@ -452,15 +450,17 @@
                                        CXXScopeSpec &SS,
                                        NamedDecl *ScopeLookupResult,
                                        bool ErrorRecoveryLookup,
-                                       bool *IsCorrectedToColon) {
+                                       NameSpecRecoveryInfo *RecovInfo) {
   LookupResult Found(*this, &Identifier, IdentifierLoc, 
                      LookupNestedNameSpecifierName);
 
   // Determine where to perform name lookup
   DeclContext *LookupCtx = nullptr;
   bool isDependent = false;
-  if (IsCorrectedToColon)
-    *IsCorrectedToColon = false;
+  if (RecovInfo) {
+    RecovInfo->CorrectionToColonRequested = false;
+    RecovInfo->FoundDecl = nullptr;
+  }
   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.
@@ -553,8 +553,8 @@
     if (!R.empty()) {
       // The identifier is found in ordinary lookup. If correction to colon is
       // allowed, suggest replacement to ':'.
-      if (IsCorrectedToColon) {
-        *IsCorrectedToColon = true;
+      if (RecovInfo && RecovInfo->CorrectToColon) {
+        RecovInfo->CorrectionToColonRequested = true;
         Diag(CCLoc, diag::err_nested_name_spec_is_not_class)
             << &Identifier << getLangOpts().CPlusPlus
             << FixItHint::CreateReplacement(CCLoc, ":");
@@ -754,10 +754,13 @@
   }
 
   if (!Found.empty()) {
-    if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
-      Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
+    if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) {
+      if (RecovInfo)
+        RecovInfo->FoundDecl = TD;
+      else
+        Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
           << QualType(TD->getTypeForDecl(), 0) << getLangOpts().CPlusPlus;
-    else {
+    } else {
       Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
           << &Identifier << getLangOpts().CPlusPlus;
       if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
@@ -780,15 +783,15 @@
                                        bool EnteringContext,
                                        CXXScopeSpec &SS,
                                        bool ErrorRecoveryLookup,
-                                       bool *IsCorrectedToColon) {
+                                       NameSpecRecoveryInfo *RecovInfo) {
   if (SS.isInvalid())
     return true;
 
   return BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, CCLoc,
                                      GetTypeFromParser(ObjectType),
                                      EnteringContext, SS, 
                                      /*ScopeLookupResult=*/nullptr, false,
-                                     IsCorrectedToColon);
+                                     RecovInfo);
 }
 
 bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
Index: test/SemaCXX/nested-name-spec.cpp
===================================================================
--- test/SemaCXX/nested-name-spec.cpp
+++ test/SemaCXX/nested-name-spec.cpp
@@ -116,7 +116,7 @@
     };
 
     void f() {
-      return E::X; // expected-error{{'E::Nested::E' is not a class, namespace, or scoped enumeration}}
+      return E::X; // expected-error{{unscoped enumeration name shall not be specified in nested name specifier}}
     }
   }
 }
@@ -410,3 +410,15 @@
 };
 
 }
+
+
+namespace PR16951 {
+  namespace ns {
+    enum an_enumeration {
+      ENUMERATOR
+    };
+  }
+
+  int x1 = ns::an_enumeration::ENUMERATOR; // expected-error{{unscoped enumeration name shall not be specified in nested name specifier}}
+  int x2 = ns::an_enumeration::ENUMERATOR::vvv; // expected-error{{'PR16951::ns::an_enumeration' is not a class, namespace, or scoped enumeration}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to