]> granicus.if.org Git - clang/commitdiff
Handle unscoped enumeration in nested name specifier.
authorSerge Pavlov <sepavloff@gmail.com>
Sun, 18 Jan 2015 20:04:35 +0000 (20:04 +0000)
committerSerge Pavlov <sepavloff@gmail.com>
Sun, 18 Jan 2015 20:04:35 +0000 (20:04 +0000)
If an unscoped enum is used as a nested name specifier and the language dialect
is not C++ 11, issue an extension warning.
This fixes PR16951.

Differential Revision: http://reviews.llvm.org/D6389

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@226413 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Sema.h
lib/Sema/SemaCXXScopeSpec.cpp
test/SemaCXX/member-pointer.cpp
test/SemaCXX/nested-name-spec.cpp

index 1bcd702ad8c309af3aec488184d7e8bdd47faef0..5d958a626724974d3f4ebe41ffa53d39573db9cc 100644 (file)
@@ -1231,6 +1231,9 @@ def warn_cxx98_compat_enum_nested_name_spec : Warning<
 def err_nested_name_spec_is_not_class : Error<
   "%0 cannot appear before '::' because it is not a class"
   "%select{ or namespace|, namespace, or enumeration}1; did you mean ':'?">;
+def ext_nested_name_spec_is_enum : ExtWarn<
+  "use of enumeration in a nested name specifier is a C++11 extension">,
+  InGroup<CXX11>;
 
 // C++ class members
 def err_storageclass_invalid_for_member : Error<
index 9aed52a22dd9a4a5d1518c4cde6972f9929d4c71..0cabb3b43a178312307cf6b8179a3e7b4260ca29 100644 (file)
@@ -4632,7 +4632,8 @@ public:
   bool ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
                                 SourceLocation ColonColonLoc, CXXScopeSpec &SS);
 
-  bool isAcceptableNestedNameSpecifier(const NamedDecl *SD);
+  bool isAcceptableNestedNameSpecifier(const NamedDecl *SD,
+                                       bool *CanCorrect = nullptr);
   NamedDecl *FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS);
 
   bool isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS,
index 3e56e676a15c58fb8c5164949703cabb5894b79e..438ad61ee9bf2b4c724d34bbcdc347ba895618a1 100644 (file)
@@ -282,7 +282,11 @@ bool Sema::ActOnSuperScopeSpecifier(SourceLocation SuperLoc,
 
 /// \brief Determines whether the given declaration is an valid acceptable
 /// result for name lookup of a nested-name-specifier.
-bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
+/// \param SD Declaration checked for nested-name-specifier.
+/// \param IsExtension If not null and the declaration is accepted as an
+/// extension, the pointed variable is assigned true.
+bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD,
+                                           bool *IsExtension) {
   if (!SD)
     return false;
 
@@ -298,14 +302,23 @@ bool Sema::isAcceptableNestedNameSpecifier(const NamedDecl *SD) {
   QualType T = Context.getTypeDeclType(cast<TypeDecl>(SD));
   if (T->isDependentType())
     return true;
-  else if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
-    if (TD->getUnderlyingType()->isRecordType() ||
-        (Context.getLangOpts().CPlusPlus11 &&
-         TD->getUnderlyingType()->isEnumeralType()))
+  if (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(SD)) {
+    if (TD->getUnderlyingType()->isRecordType())
       return true;
-  } else if (isa<RecordDecl>(SD) ||
-             (Context.getLangOpts().CPlusPlus11 && isa<EnumDecl>(SD)))
+    if (TD->getUnderlyingType()->isEnumeralType()) {
+      if (Context.getLangOpts().CPlusPlus11)
+        return true;
+      if (IsExtension)
+        *IsExtension = true;
+    }
+  } else if (isa<RecordDecl>(SD)) {
     return true;
+  } else if (isa<EnumDecl>(SD)) {
+    if (Context.getLangOpts().CPlusPlus11)
+      return true;
+    if (IsExtension)
+      *IsExtension = true;
+  }
 
   return false;
 }
@@ -599,7 +612,13 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
   }
 
   NamedDecl *SD = Found.getAsSingle<NamedDecl>();
-  if (isAcceptableNestedNameSpecifier(SD)) {
+  bool IsExtension = false;
+  bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension);
+  if (!AcceptSpec && IsExtension) {
+    AcceptSpec = true;
+    Diag(IdentifierLoc, diag::ext_nested_name_spec_is_enum);
+  }
+  if (AcceptSpec) {
     if (!ObjectType.isNull() && !ObjectTypeSearchedInScope &&
         !getLangOpts().CPlusPlus11) {
       // C++03 [basic.lookup.classref]p4:
index f8834e37de301a77926dc611c626cd88c86fbc25..b9e5a631baa2d860dbbeecfe13e18be55d979eb4 100644 (file)
@@ -13,7 +13,8 @@ int A::*pdi1;
 int (::A::*pdi2);
 int (A::*pfi)(int);
 
-int B::*pbi; // expected-error {{'B' is not a class, namespace, or enumeration}}
+int B::*pbi; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \
+             // expected-error {{'pbi' does not point into a class}}
 int C::*pci; // expected-error {{'pci' does not point into a class}}
 void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}}
 int& A::*pdr; // expected-error {{'pdr' declared as a member pointer to a reference}}
index 15d63e10a9106a1ebeb19ec9af15022b33d7503d..0fbdedc70a690d3b65d4c7ad73eee3aa3dc0c681 100644 (file)
@@ -115,8 +115,8 @@ namespace E {
       X = 0
     };
 
-    void f() {
-      return E::X; // expected-error{{'E::Nested::E' is not a class, namespace, or enumeration}}
+    int f() {
+      return E::X; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}}
     }
   }
 }
@@ -410,3 +410,28 @@ struct S7c {
 };
 
 }
+
+namespace PR16951 {
+  namespace ns {
+    enum an_enumeration {
+      ENUMERATOR  // expected-note{{'ENUMERATOR' declared here}}
+    };
+  }
+
+  int x1 = ns::an_enumeration::ENUMERATOR; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}}
+
+  int x2 = ns::an_enumeration::ENUMERATOR::vvv; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \
+                                                // expected-error{{'ENUMERATOR' is not a class, namespace, or enumeration}} \
+
+  int x3 = ns::an_enumeration::X; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \
+                                  // expected-error{{no member named 'X'}}
+
+  enum enumerator_2 {
+    ENUMERATOR_2
+  };
+
+  int x4 = enumerator_2::ENUMERATOR_2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}}
+  int x5 = enumerator_2::X2; // expected-warning{{use of enumeration in a nested name specifier is a C++11 extension}} \
+                             // expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}}
+
+}