diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 14 | ||||
-rw-r--r-- | test/SemaCXX/enum-unscoped-nonexistent.cpp | 39 |
3 files changed, 58 insertions, 0 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 36232b1e98..7df189d5f9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3542,6 +3542,11 @@ def err_member_not_yet_instantiated : Error< def note_non_instantiated_member_here : Note< "not-yet-instantiated member is declared here">; +def err_enumerator_does_not_exist : Error< + "enumerator %0 does not exist in instantiation of %1">; +def note_enum_specialized_here : Note< + "enum %0 was explicitly specialized here">; + def err_member_redeclared : Error<"class member cannot be redeclared">; def err_member_name_of_class : Error<"member %0 has the same name as its class">; def err_member_def_undefined_record : Error< diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 8729a39f9b..e767f6a7d9 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3289,6 +3289,20 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, << D->getDeclName() << Context.getTypeDeclType(cast<CXXRecordDecl>(ParentDC)); Diag(D->getLocation(), diag::note_non_instantiated_member_here); + } else if (EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) { + // This enumeration constant was found when the template was defined, + // but can't be found in the instantiation. This can happen if an + // unscoped enumeration member is explicitly specialized. + EnumDecl *Enum = cast<EnumDecl>(ED->getLexicalDeclContext()); + EnumDecl *Spec = cast<EnumDecl>(FindInstantiatedDecl(Loc, Enum, + TemplateArgs)); + assert(Spec->getTemplateSpecializationKind() == + TSK_ExplicitSpecialization); + Diag(Loc, diag::err_enumerator_does_not_exist) + << D->getDeclName() + << Context.getTypeDeclType(cast<TypeDecl>(Spec->getDeclContext())); + Diag(Spec->getLocation(), diag::note_enum_specialized_here) + << Context.getTypeDeclType(Spec); } else { // We should have found something, but didn't. llvm_unreachable("Unable to find instantiation of declaration!"); diff --git a/test/SemaCXX/enum-unscoped-nonexistent.cpp b/test/SemaCXX/enum-unscoped-nonexistent.cpp new file mode 100644 index 0000000000..d49800caa6 --- /dev/null +++ b/test/SemaCXX/enum-unscoped-nonexistent.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -std=c++11 -verify %s + +struct Base { + static const int a = 1; +}; +template<typename T> struct S : Base { + enum E : int; + constexpr int f(); + constexpr int g(); // expected-note {{declared here}} + void h(); +}; +template<> enum S<char>::E : int {}; // expected-note {{enum 'S<char>::E' was explicitly specialized here}} +template<> enum S<short>::E : int { b = 2 }; +template<> enum S<int>::E : int { a = 4 }; +template<typename T> enum S<T>::E : int { b = 8 }; + +// The unqualified-id here names a member of the non-dependent base class Base +// and not the injected enumerator name 'a' from the specialization. +template<typename T> constexpr int S<T>::f() { return a; } +static_assert(S<char>().f() == 1, ""); +static_assert(S<int>().f() == 1, ""); + +// The unqualified-id here names a member of the current instantiation, which +// bizarrely might not exist in some instantiations. +template<typename T> constexpr int S<T>::g() { return b; } // expected-error {{enumerator 'b' does not exist in instantiation of 'S<char>'}} +static_assert(S<char>().g() == 1, ""); // expected-note {{here}} expected-error {{not an integral constant expression}} expected-note {{undefined}} +static_assert(S<short>().g() == 2, ""); +static_assert(S<long>().g() == 8, ""); + +// 'b' is type-dependent, so these assertions should not fire before 'h' is +// instantiated. +template<typename T> void S<T>::h() { + char c[S<T>::b]; + static_assert(b != 8, ""); + static_assert(sizeof(c) != 8, ""); +} +void f() { + S<short>().h(); // ok, b == 2 +} |