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

llvm-svn: 226413
This commit is contained in:
Serge Pavlov 2015-01-18 20:04:35 +00:00
parent 4843f193ad
commit 25a8afa957
5 changed files with 61 additions and 12 deletions

View 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<

View 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,

View 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:

View 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}}

View 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'}}
}