forked from OSchip/llvm-project
When diagnosing C++ [temp.expl.spec]p3 in C++98/03 mode, downgrade the
error to a warning if we're in a case that would be allowed in C++0x. This "fixes" PR8084 by making Clang accept more code than GCC and (non-strict) EDG do. Also, add the missing test case for the C++0x semantics, which should have been in r113717. llvm-svn: 113718
This commit is contained in:
parent
b1aab43887
commit
8ce63154d0
|
@ -1459,10 +1459,18 @@ def err_template_spec_decl_out_of_scope_global : Error<
|
|||
"%select{class template|class template partial|function template|member "
|
||||
"function|static data member|member class}0 specialization of %1 must "
|
||||
"originally be declared in the global scope">;
|
||||
def ext_template_spec_decl_out_of_scope_global : ExtWarn<
|
||||
"%select{class template|class template partial|function template|member "
|
||||
"function|static data member|member class}0 specialization of %1 must "
|
||||
"originally be declared in the global scope; accepted as a C++0x extension">;
|
||||
def err_template_spec_decl_out_of_scope : Error<
|
||||
"%select{class template|class template partial|function template|member "
|
||||
"function|static data member|member class}0 specialization of %1 must "
|
||||
"originally be declared in namespace %2">;
|
||||
def ext_template_spec_decl_out_of_scope : ExtWarn<
|
||||
"%select{class template|class template partial|function template|member "
|
||||
"function|static data member|member class}0 specialization of %1 must "
|
||||
"originally be declared in namespace %2; accepted as a C++0x extension">;
|
||||
def err_template_spec_redecl_out_of_scope : Error<
|
||||
"%select{class template|class template partial|function template|member "
|
||||
"function|static data member|member class}0 specialization of %1 not in a "
|
||||
|
|
|
@ -3454,13 +3454,19 @@ static bool CheckTemplateSpecializationScope(Sema &S,
|
|||
// the specialized template.
|
||||
if (!DC->InEnclosingNamespaceSetOf(SpecializedContext) &&
|
||||
!(S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext))) {
|
||||
bool IsCPlusPlus0xExtension
|
||||
= !S.getLangOptions().CPlusPlus0x && DC->Encloses(SpecializedContext);
|
||||
if (isa<TranslationUnitDecl>(SpecializedContext))
|
||||
S.Diag(Loc, diag::err_template_spec_decl_out_of_scope_global)
|
||||
<< EntityKind << Specialized;
|
||||
S.Diag(Loc, IsCPlusPlus0xExtension
|
||||
? diag::ext_template_spec_decl_out_of_scope_global
|
||||
: diag::err_template_spec_decl_out_of_scope_global)
|
||||
<< EntityKind << Specialized;
|
||||
else if (isa<NamespaceDecl>(SpecializedContext))
|
||||
S.Diag(Loc, diag::err_template_spec_decl_out_of_scope)
|
||||
<< EntityKind << Specialized
|
||||
<< cast<NamedDecl>(SpecializedContext);
|
||||
S.Diag(Loc, IsCPlusPlus0xExtension
|
||||
? diag::ext_template_spec_decl_out_of_scope
|
||||
: diag::err_template_spec_decl_out_of_scope)
|
||||
<< EntityKind << Specialized
|
||||
<< cast<NamedDecl>(SpecializedContext);
|
||||
|
||||
S.Diag(Specialized->getLocation(), diag::note_specialized_entity);
|
||||
ComplainedAboutScope = true;
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s
|
||||
|
||||
// This test creates cases where implicit instantiations of various entities
|
||||
// would cause a diagnostic, but provides expliict specializations for those
|
||||
// entities that avoid the diagnostic. The specializations are alternately
|
||||
// declarations and definitions, and the intent of this test is to verify
|
||||
// that we allow specializations only in the appropriate namespaces (and
|
||||
// nowhere else).
|
||||
struct NonDefaultConstructible {
|
||||
NonDefaultConstructible(int);
|
||||
};
|
||||
|
||||
|
||||
// C++ [temp.expl.spec]p1:
|
||||
// An explicit specialization of any of the following:
|
||||
|
||||
// -- function template
|
||||
namespace N0 {
|
||||
template<typename T> void f0(T) {
|
||||
T t;
|
||||
}
|
||||
|
||||
template<> void f0(NonDefaultConstructible) { }
|
||||
|
||||
void test_f0(NonDefaultConstructible NDC) {
|
||||
f0(NDC);
|
||||
}
|
||||
|
||||
template<> void f0(int);
|
||||
template<> void f0(long);
|
||||
}
|
||||
|
||||
template<> void N0::f0(int) { } // okay
|
||||
|
||||
namespace N1 {
|
||||
template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
|
||||
}
|
||||
|
||||
template<> void N0::f0(double) { }
|
||||
|
||||
struct X1 {
|
||||
template<typename T> void f(T);
|
||||
|
||||
template<> void f(int); // expected-error{{in class scope}}
|
||||
};
|
||||
|
||||
// -- class template
|
||||
namespace N0 {
|
||||
|
||||
template<typename T>
|
||||
struct X0 { // expected-note {{here}}
|
||||
static T member;
|
||||
|
||||
void f1(T t) {
|
||||
t = 17;
|
||||
}
|
||||
|
||||
struct Inner : public T { }; // expected-note 2{{here}}
|
||||
|
||||
template<typename U>
|
||||
struct InnerTemplate : public T { }; // expected-note 1{{explicitly specialized}} \
|
||||
// expected-error{{base specifier}}
|
||||
|
||||
template<typename U>
|
||||
void ft1(T t, U u);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
template<typename U>
|
||||
void N0::X0<T>::ft1(T t, U u) {
|
||||
t = u;
|
||||
}
|
||||
|
||||
template<typename T> T N0::X0<T>::member;
|
||||
|
||||
template<> struct N0::X0<void> { };
|
||||
N0::X0<void> test_X0;
|
||||
|
||||
namespace N1 {
|
||||
template<> struct N0::X0<const void> { }; // expected-error{{class template specialization of 'X0' must originally be declared in namespace 'N0'}}
|
||||
}
|
||||
|
||||
namespace N0 {
|
||||
template<> struct X0<volatile void>;
|
||||
}
|
||||
|
||||
template<> struct N0::X0<volatile void> {
|
||||
void f1(void *);
|
||||
};
|
||||
|
||||
// -- member function of a class template
|
||||
template<> void N0::X0<void*>::f1(void *) { }
|
||||
|
||||
void test_spec(N0::X0<void*> xvp, void *vp) {
|
||||
xvp.f1(vp);
|
||||
}
|
||||
|
||||
namespace N0 {
|
||||
template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}}
|
||||
|
||||
template<> void X0<const volatile void*>::f1(const volatile void*);
|
||||
}
|
||||
|
||||
void test_x0_cvvoid(N0::X0<const volatile void*> x0, const volatile void *cvp) {
|
||||
x0.f1(cvp); // okay: we've explicitly specialized
|
||||
}
|
||||
|
||||
// -- static data member of a class template
|
||||
namespace N0 {
|
||||
// This actually tests p15; the following is a declaration, not a definition.
|
||||
template<>
|
||||
NonDefaultConstructible X0<NonDefaultConstructible>::member;
|
||||
|
||||
template<> long X0<long>::member = 17;
|
||||
|
||||
template<> float X0<float>::member;
|
||||
|
||||
template<> double X0<double>::member;
|
||||
}
|
||||
|
||||
NonDefaultConstructible &get_static_member() {
|
||||
return N0::X0<NonDefaultConstructible>::member;
|
||||
}
|
||||
|
||||
template<> int N0::X0<int>::member;
|
||||
|
||||
template<> float N0::X0<float>::member = 3.14f;
|
||||
|
||||
namespace N1 {
|
||||
template<> double N0::X0<double>::member = 3.14; // expected-error{{not in a namespace enclosing}}
|
||||
}
|
||||
|
||||
// -- member class of a class template
|
||||
namespace N0 {
|
||||
|
||||
template<>
|
||||
struct X0<void*>::Inner { };
|
||||
|
||||
template<>
|
||||
struct X0<int>::Inner { };
|
||||
|
||||
template<>
|
||||
struct X0<unsigned>::Inner;
|
||||
|
||||
template<>
|
||||
struct X0<float>::Inner;
|
||||
|
||||
template<>
|
||||
struct X0<double>::Inner; // expected-note{{forward declaration}}
|
||||
}
|
||||
|
||||
template<>
|
||||
struct N0::X0<long>::Inner { };
|
||||
|
||||
template<>
|
||||
struct N0::X0<float>::Inner { };
|
||||
|
||||
namespace N1 {
|
||||
template<>
|
||||
struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}}
|
||||
|
||||
template<>
|
||||
struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}}
|
||||
};
|
||||
|
||||
N0::X0<void*>::Inner inner0;
|
||||
N0::X0<int>::Inner inner1;
|
||||
N0::X0<long>::Inner inner2;
|
||||
N0::X0<float>::Inner inner3;
|
||||
N0::X0<double>::Inner inner4; // expected-error{{incomplete}}
|
||||
|
||||
// -- member class template of a class template
|
||||
namespace N0 {
|
||||
template<>
|
||||
template<>
|
||||
struct X0<void*>::InnerTemplate<int> { };
|
||||
|
||||
template<> template<>
|
||||
struct X0<int>::InnerTemplate<int>; // expected-note{{forward declaration}}
|
||||
|
||||
template<> template<>
|
||||
struct X0<int>::InnerTemplate<long>;
|
||||
|
||||
template<> template<>
|
||||
struct X0<int>::InnerTemplate<double>;
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
struct N0::X0<int>::InnerTemplate<long> { }; // okay
|
||||
|
||||
template<> template<>
|
||||
struct N0::X0<int>::InnerTemplate<float> { };
|
||||
|
||||
namespace N1 {
|
||||
template<> template<>
|
||||
struct N0::X0<int>::InnerTemplate<double> { }; // expected-error{{enclosing}}
|
||||
}
|
||||
|
||||
N0::X0<void*>::InnerTemplate<int> inner_template0;
|
||||
N0::X0<int>::InnerTemplate<int> inner_template1; // expected-error{{incomplete}}
|
||||
N0::X0<int>::InnerTemplate<long> inner_template2;
|
||||
N0::X0<int>::InnerTemplate<unsigned long> inner_template3; // expected-note{{instantiation}}
|
||||
|
||||
// -- member function template of a class template
|
||||
namespace N0 {
|
||||
template<>
|
||||
template<>
|
||||
void X0<void*>::ft1(void*, const void*) { }
|
||||
|
||||
template<> template<>
|
||||
void X0<void*>::ft1(void *, int);
|
||||
|
||||
template<> template<>
|
||||
void X0<void*>::ft1(void *, unsigned);
|
||||
|
||||
template<> template<>
|
||||
void X0<void*>::ft1(void *, long);
|
||||
}
|
||||
|
||||
template<> template<>
|
||||
void N0::X0<void*>::ft1(void *, unsigned) { } // okay
|
||||
|
||||
template<> template<>
|
||||
void N0::X0<void*>::ft1(void *, float) { }
|
||||
|
||||
namespace N1 {
|
||||
template<> template<>
|
||||
void N0::X0<void*>::ft1(void *, long) { } // expected-error{{enclosing}}
|
||||
}
|
||||
|
||||
|
||||
void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp,
|
||||
int i, unsigned u) {
|
||||
xvp.ft1(vp, cvp);
|
||||
xvp.ft1(vp, i);
|
||||
xvp.ft1(vp, u);
|
||||
}
|
|
@ -36,7 +36,7 @@ namespace N1 {
|
|||
template<> void N0::f0(long) { } // expected-error{{not in a namespace enclosing}}
|
||||
}
|
||||
|
||||
template<> void N0::f0(double) { } // expected-error{{originally be declared}}
|
||||
template<> void N0::f0(double) { } // expected-warning{{originally be declared}}
|
||||
|
||||
struct X1 {
|
||||
template<typename T> void f(T);
|
||||
|
@ -75,7 +75,7 @@ void N0::X0<T>::ft1(T t, U u) {
|
|||
|
||||
template<typename T> T N0::X0<T>::member;
|
||||
|
||||
template<> struct N0::X0<void> { }; // expected-error{{originally}}
|
||||
template<> struct N0::X0<void> { }; // expected-warning{{originally}}
|
||||
N0::X0<void> test_X0;
|
||||
|
||||
namespace N1 {
|
||||
|
@ -91,7 +91,7 @@ template<> struct N0::X0<volatile void> {
|
|||
};
|
||||
|
||||
// -- member function of a class template
|
||||
template<> void N0::X0<void*>::f1(void *) { } // expected-error{{member function specialization}}
|
||||
template<> void N0::X0<void*>::f1(void *) { } // expected-warning{{member function specialization}}
|
||||
|
||||
void test_spec(N0::X0<void*> xvp, void *vp) {
|
||||
xvp.f1(vp);
|
||||
|
@ -124,7 +124,7 @@ NonDefaultConstructible &get_static_member() {
|
|||
return N0::X0<NonDefaultConstructible>::member;
|
||||
}
|
||||
|
||||
template<> int N0::X0<int>::member; // expected-error{{originally}}
|
||||
template<> int N0::X0<int>::member; // expected-warning{{originally}}
|
||||
|
||||
template<> float N0::X0<float>::member = 3.14f;
|
||||
|
||||
|
@ -152,7 +152,7 @@ namespace N0 {
|
|||
}
|
||||
|
||||
template<>
|
||||
struct N0::X0<long>::Inner { }; // expected-error{{originally}}
|
||||
struct N0::X0<long>::Inner { }; // expected-warning{{originally}}
|
||||
|
||||
template<>
|
||||
struct N0::X0<float>::Inner { };
|
||||
|
@ -191,7 +191,7 @@ template<> template<>
|
|||
struct N0::X0<int>::InnerTemplate<long> { }; // okay
|
||||
|
||||
template<> template<>
|
||||
struct N0::X0<int>::InnerTemplate<float> { }; // expected-error{{class template specialization}}
|
||||
struct N0::X0<int>::InnerTemplate<float> { }; // expected-warning{{class template specialization}}
|
||||
|
||||
namespace N1 {
|
||||
template<> template<>
|
||||
|
@ -223,7 +223,7 @@ template<> template<>
|
|||
void N0::X0<void*>::ft1(void *, unsigned) { } // okay
|
||||
|
||||
template<> template<>
|
||||
void N0::X0<void*>::ft1(void *, float) { } // expected-error{{function template specialization}}
|
||||
void N0::X0<void*>::ft1(void *, float) { } // expected-warning{{function template specialization}}
|
||||
|
||||
namespace N1 {
|
||||
template<> template<>
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace N {
|
|||
|
||||
template<> struct N::B<int> { }; // okay
|
||||
|
||||
template<> struct N::B<float> { }; // expected-error{{originally}}
|
||||
template<> struct N::B<float> { }; // expected-warning{{originally}}
|
||||
|
||||
namespace M {
|
||||
template<> struct ::N::B<short> { }; // expected-error{{class template specialization of 'B' not in a namespace enclosing 'N'}}
|
||||
|
|
|
@ -9,7 +9,7 @@ namespace N {
|
|||
}
|
||||
|
||||
template<typename T>
|
||||
struct N::M::A<T*> { }; // expected-error{{originally}}
|
||||
struct N::M::A<T*> { }; // expected-warning{{originally}}
|
||||
|
||||
// C++ [temp.class.spec]p9
|
||||
// bullet 1
|
||||
|
|
Loading…
Reference in New Issue