Updated patch.
Instead of providing removal fixit, issue extension warning.
http://reviews.llvm.org/D6389
Files:
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
EMAIL PREFERENCES
http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -1228,6 +1228,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 scoped enumeration}1; did you mean ':'?">;
+def ext_nested_name_spec_is_enum : ExtWarn<
+ "use of unscoped enumeration in a nested name specifier is a C++11 extension">,
+ InGroup<CXX11>;
// C++ class members
def err_storageclass_invalid_for_member : Error<
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ 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: lib/Sema/SemaCXXScopeSpec.cpp
===================================================================
--- lib/Sema/SemaCXXScopeSpec.cpp
+++ 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 may be used in extended
+/// syntax, 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<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 @@
}
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: test/SemaCXX/member-pointer.cpp
===================================================================
--- test/SemaCXX/member-pointer.cpp
+++ 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 scoped enumeration}}
+int B::*pbi; // expected-warning{{use of unscoped 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: test/SemaCXX/nested-name-spec.cpp
===================================================================
--- test/SemaCXX/nested-name-spec.cpp
+++ 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 scoped enumeration}}
+ int f() {
+ return E::X; // expected-warning{{use of unscoped 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 unscoped enumeration in a nested name specifier is a C++11 extension}}
+
+ int x2 = ns::an_enumeration::ENUMERATOR::vvv; // expected-warning{{use of unscoped enumeration in a nested name specifier is a C++11 extension}} \
+ // expected-error{{'ENUMERATOR' is not a class, namespace, or scoped enumeration}} \
+
+ int x3 = ns::an_enumeration::X; // expected-warning{{use of unscoped 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 unscoped enumeration in a nested name specifier is a C++11 extension}}
+ int x5 = enumerator_2::X2; // expected-warning{{use of unscoped enumeration in a nested name specifier is a C++11 extension}} \
+ // expected-error{{no member named 'X2' in 'PR16951::enumerator_2'}}
+
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits