Index: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td @@ -1231,6 +1231,9 @@ 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; // C++ class members def err_storageclass_invalid_for_member : Error< Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/include/clang/Sema/Sema.h @@ -4632,7 +4632,8 @@ 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: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp +++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp @@ -282,7 +282,11 @@ /// \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 @@ QualType T = Context.getTypeDeclType(cast(SD)); if (T->isDependentType()) return true; - else if (const TypedefNameDecl *TD = dyn_cast(SD)) { - if (TD->getUnderlyingType()->isRecordType() || - (Context.getLangOpts().CPlusPlus11 && - TD->getUnderlyingType()->isEnumeralType())) + if (const TypedefNameDecl *TD = dyn_cast(SD)) { + if (TD->getUnderlyingType()->isRecordType()) return true; - } else if (isa(SD) || - (Context.getLangOpts().CPlusPlus11 && isa(SD))) + if (TD->getUnderlyingType()->isEnumeralType()) { + if (Context.getLangOpts().CPlusPlus11) + return true; + if (IsExtension) + *IsExtension = true; + } + } else if (isa(SD)) { return true; + } else if (isa(SD)) { + if (Context.getLangOpts().CPlusPlus11) + return true; + if (IsExtension) + *IsExtension = true; + } return false; } @@ -599,7 +612,13 @@ } NamedDecl *SD = Found.getAsSingle(); - 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: cfe/trunk/test/SemaCXX/member-pointer.cpp =================================================================== --- cfe/trunk/test/SemaCXX/member-pointer.cpp +++ cfe/trunk/test/SemaCXX/member-pointer.cpp @@ -13,7 +13,8 @@ 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: cfe/trunk/test/SemaCXX/nested-name-spec.cpp =================================================================== --- cfe/trunk/test/SemaCXX/nested-name-spec.cpp +++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp @@ -115,8 +115,8 @@ 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 @@ }; } + +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'}} + +}