From: Serge Pavlov Date: Sun, 18 Jan 2015 20:04:35 +0000 (+0000) Subject: Handle unscoped enumeration in nested name specifier. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=217c370a90abf060ecc908d63648a3fe74916ec7;p=clang Handle unscoped enumeration in nested name specifier. 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 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 1bcd702ad8..5d958a6267 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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; // C++ class members def err_storageclass_invalid_for_member : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 9aed52a22d..0cabb3b43a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 3e56e676a1..438ad61ee9 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -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(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 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, } 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: diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index f8834e37de..b9e5a631ba 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -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}} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 15d63e10a9..0fbdedc70a 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -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'}} + +}