r191278 - Implement restriction that a partial specialization must actually specialize
Richard Smith
richard-llvm at metafoo.co.uk
Mon Sep 23 21:49:24 PDT 2013
Author: rsmith
Date: Mon Sep 23 23:49:23 2013
New Revision: 191278
URL: http://llvm.org/viewvc/llvm-project?rev=191278&view=rev
Log:
Implement restriction that a partial specialization must actually specialize
something, for variable templates.
Added:
cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
cfe/trunk/test/PCH/cxx1y-variable-templates.cpp
cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
cfe/trunk/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=191278&r1=191277&r2=191278&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Sep 23 23:49:23 2013
@@ -3127,12 +3127,12 @@ def err_dependent_typed_non_type_arg_in_
"non-type template argument specializes a template parameter with "
"dependent type %0">;
def err_partial_spec_args_match_primary_template : Error<
- "class template partial specialization does not specialize any template "
- "argument; to %select{declare|define}0 the primary template, remove the "
- "template argument list">;
+ "%select{class|variable}0 template partial specialization does not "
+ "specialize any template argument; to %select{declare|define}1 the "
+ "primary template, remove the template argument list">;
def warn_partial_specs_not_deducible : Warning<
- "class template partial specialization contains "
- "%select{a template parameter|template parameters}0 that can not be "
+ "%select{class|variable}0 template partial specialization contains "
+ "%select{a template parameter|template parameters}1 that can not be "
"deduced; this partial specialization will never be used">;
def note_partial_spec_unused_parameter : Note<
"non-deducible template parameter %0">;
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=191278&r1=191277&r2=191278&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Sep 23 23:49:23 2013
@@ -2273,6 +2273,69 @@ static bool CheckTemplateSpecializationS
static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D);
+static bool isTemplateArgumentTemplateParameter(
+ const TemplateArgument &Arg, unsigned Depth, unsigned Index) {
+ switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::Pack:
+ case TemplateArgument::TemplateExpansion:
+ return false;
+
+ case TemplateArgument::Type: {
+ QualType Type = Arg.getAsType();
+ const TemplateTypeParmType *TPT =
+ Arg.getAsType()->getAs<TemplateTypeParmType>();
+ return TPT && !Type.hasQualifiers() &&
+ TPT->getDepth() == Depth && TPT->getIndex() == Index;
+ }
+
+ case TemplateArgument::Expression: {
+ DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg.getAsExpr());
+ if (!DRE || !DRE->getDecl())
+ return false;
+ const NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl());
+ return NTTP && NTTP->getDepth() == Depth && NTTP->getIndex() == Index;
+ }
+
+ case TemplateArgument::Template:
+ const TemplateTemplateParmDecl *TTP =
+ dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Arg.getAsTemplateOrTemplatePattern().getAsTemplateDecl());
+ return TTP && TTP->getDepth() == Depth && TTP->getIndex() == Index;
+ }
+ llvm_unreachable("unexpected kind of template argument");
+}
+
+static bool isSameAsPrimaryTemplate(TemplateParameterList *Params,
+ ArrayRef<TemplateArgument> Args) {
+ if (Params->size() != Args.size())
+ return false;
+
+ unsigned Depth = Params->getDepth();
+
+ for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+ TemplateArgument Arg = Args[I];
+
+ // If the parameter is a pack expansion, the argument must be a pack
+ // whose only element is a pack expansion.
+ if (Params->getParam(I)->isParameterPack()) {
+ if (Arg.getKind() != TemplateArgument::Pack || Arg.pack_size() != 1 ||
+ !Arg.pack_begin()->isPackExpansion())
+ return false;
+ Arg = Arg.pack_begin()->getPackExpansionPattern();
+ }
+
+ if (!isTemplateArgumentTemplateParameter(Arg, Depth, I))
+ return false;
+ }
+
+ return true;
+}
+
DeclResult Sema::ActOnVarTemplateSpecialization(
Scope *S, VarTemplateDecl *VarTemplate, Declarator &D, TypeSourceInfo *DI,
SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams,
@@ -2341,6 +2404,21 @@ DeclResult Sema::ActOnVarTemplateSpecial
<< VarTemplate->getDeclName();
IsPartialSpecialization = false;
}
+
+ if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(),
+ Converted)) {
+ // C++ [temp.class.spec]p9b3:
+ //
+ // -- The argument list of the specialization shall not be identical
+ // to the implicit argument list of the primary template.
+ Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
+ << /*variable template*/ 1
+ << /*is definition*/(SC != SC_Extern && !CurContext->isRecord())
+ << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
+ // FIXME: Recover from this by treating the declaration as a redeclaration
+ // of the primary template.
+ return true;
+ }
}
void *InsertPos = 0;
@@ -2402,7 +2480,8 @@ DeclResult Sema::ActOnVarTemplateSpecial
unsigned NumNonDeducible =
DeducibleParams.size() - DeducibleParams.count();
Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
- << (NumNonDeducible > 1) << SourceRange(TemplateNameLoc, RAngleLoc);
+ << /*variable template*/ 1 << (NumNonDeducible > 1)
+ << SourceRange(TemplateNameLoc, RAngleLoc);
for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
if (!DeducibleParams[I]) {
NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I));
@@ -5881,7 +5960,7 @@ Sema::ActOnClassTemplateSpecialization(S
// -- The argument list of the specialization shall not be identical
// to the implicit argument list of the primary template.
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
- << (TUK == TUK_Definition)
+ << /*class template*/0 << (TUK == TUK_Definition)
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
return CheckClassTemplate(S, TagSpec, TUK, KWLoc, SS,
ClassTemplate->getIdentifier(),
@@ -5935,7 +6014,7 @@ Sema::ActOnClassTemplateSpecialization(S
if (!DeducibleParams.all()) {
unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count();
Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible)
- << (NumNonDeducible > 1)
+ << /*class template*/0 << (NumNonDeducible > 1)
<< SourceRange(TemplateNameLoc, RAngleLoc);
for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) {
if (!DeducibleParams[I]) {
Added: cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp?rev=191278&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.class.spec/p8-1y.cpp Mon Sep 23 23:49:23 2013
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 -std=c++1y -fsyntax-only -verify %s
+
+// -- The argument list of the specialization shall not be identical
+// to the implicit argument list of the primary template.
+
+template<typename T, int N, template<typename> class X> int v1;
+template<typename T, int N, template<typename> class X> int v1<T, N, X>;
+// expected-error at -1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<typename...T> int v2;
+template<typename...T> int v2<T...>;
+// expected-error at -1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<int...N> int v3;
+template<int...N> int v3<N...>;
+// expected-error at -1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<template<typename> class...X> int v4;
+template<template<typename> class...X> int v4<X...>;
+// expected-error at -1{{variable template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list}}
+
+template<typename Outer> struct X {
+ template<typename Inner> static int y;
+ template<typename Inner> static int y<Outer>; // expected-warning {{can not be deduced}} expected-note {{'Inner'}}
+ template<typename Inner> static int y<Inner>; // expected-error {{does not specialize}}
+};
+template<typename Outer> template<typename Inner> int X<Outer>::y<Outer>; // expected-warning {{can not be deduced}} expected-note {{'Inner'}}
+template<typename Outer> template<typename Inner> int X<Outer>::y<Inner>; // expected-error {{does not specialize}}
+template<> template<typename Inner> int X<int>::y<Inner>; // expected-error {{does not specialize}}
Modified: cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp?rev=191278&r1=191277&r2=191278&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/static-member-variable-explicit-specialization.cpp Mon Sep 23 23:49:23 2013
@@ -49,7 +49,7 @@ template struct a<int>;
struct b {
template <typename T> static T i;
};
-template<typename T> T b::i<T> = foo();
+template<typename T> T b::i = foo();
template int b::i<int>;
}
// CHECK: define internal void @[[unordered1]]
Modified: cfe/trunk/test/PCH/cxx1y-variable-templates.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/cxx1y-variable-templates.cpp?rev=191278&r1=191277&r2=191278&view=diff
==============================================================================
--- cfe/trunk/test/PCH/cxx1y-variable-templates.cpp (original)
+++ cfe/trunk/test/PCH/cxx1y-variable-templates.cpp Mon Sep 23 23:49:23 2013
@@ -58,7 +58,7 @@ namespace spec {
template<typename T> T vc = T();
template<typename T> constexpr T vd = T(10);
- template<typename T> T* vd<T> = new T();
+ template<typename T> T* vd<T*> = new T();
}
namespace spec_join1 {
@@ -72,7 +72,7 @@ namespace spec_join1 {
template<typename T> T vc = T(10);
template<typename T> T vd = T(10);
- template<typename T> extern T* vd<T>;
+ template<typename T> extern T* vd<T*>;
}
#endif
@@ -108,7 +108,7 @@ namespace spec_join1 {
template int vc<int>;
template<typename T> extern T vd;
- template<typename T> T* vd<T> = new T();
+ template<typename T> T* vd<T*> = new T();
}
#endif
@@ -146,16 +146,16 @@ namespace spec {
static_assert(va<float> == 1.5, "");
static_assert(va<int> == 10, "");
- template<typename T> T* vb<T> = new T();
- int* intpb = vb<int>;
+ template<typename T> T* vb<T*> = new T();
+ int* intpb = vb<int*>;
static_assert(vb<float> == 1.5, "");
- template<typename T> T* vc<T> = new T();
+ template<typename T> T* vc<T*> = new T();
template<> constexpr float vc<float> = 1.5;
- int* intpc = vc<int>;
+ int* intpc = vc<int*>;
static_assert(vc<float> == 1.5, "");
- char* intpd = vd<char>;
+ char* intpd = vd<char*>;
}
namespace spec_join1 {
@@ -165,7 +165,7 @@ namespace spec_join1 {
template<typename T> extern T vb;
int b = vb<int>;
- int* intpb = vd<int>;
+ int* intpb = vd<int*>;
}
#endif
Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp?rev=191278&r1=191277&r2=191278&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_in_class.cpp Mon Sep 23 23:49:23 2013
@@ -101,29 +101,29 @@ namespace non_const_init {
struct C1a {
template<typename U> static U Data;
- template<typename U> static U* Data<U>; // Okay, with out-of-line definition
+ template<typename U> static U* Data<U*>; // Okay, with out-of-line definition
};
- template<typename T> T* C1a::Data<T> = new T();
- template int* C1a::Data<int>;
+ template<typename T> T* C1a::Data<T*> = new T();
+ template int* C1a::Data<int*>;
struct C1b {
template<typename U> static U Data;
- template<typename U> static CONST U* Data<U>; // Okay, with out-of-line definition
+ template<typename U> static CONST U* Data<U*>; // Okay, with out-of-line definition
};
- template<typename T> CONST T* C1b::Data<T> = (T*)(0);
- template CONST int* C1b::Data<int>;
+ template<typename T> CONST T* C1b::Data<T*> = (T*)(0);
+ template CONST int* C1b::Data<int*>;
struct C2a {
- template<typename U> static U Data;
- template<typename U> static U* Data<U> = new U(); // expected-error {{non-const static data member must be initialized out of line}}
+ template<typename U> static int Data;
+ template<typename U> static U* Data<U*> = new U(); // expected-error {{non-const static data member must be initialized out of line}}
};
- template int* C2a::Data<int>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int>' requested here}}
+ template int* C2a::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2a::Data<int *>' requested here}}
struct C2b { // FIXME: ?!? Should this be an error? pointer-types are automatically non-const?
- template<typename U> static U Data;
- template<typename U> static CONST U* Data<U> = (U*)(0); // expected-error {{non-const static data member must be initialized out of line}}
+ template<typename U> static int Data;
+ template<typename U> static CONST U* Data<U*> = (U*)(0); // expected-error {{non-const static data member must be initialized out of line}}
};
- template CONST int* C2b::Data<int>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int>' requested here}}
+ template CONST int* C2b::Data<int*>; // expected-note {{in instantiation of static data member 'non_const_init::pointers::C2b::Data<int *>' requested here}}
}
}
@@ -211,16 +211,17 @@ namespace in_class_template {
}
namespace other_bugs {
- // FIXME: This fails to properly initialize the variable 'k'.
-
+ // FIXME: This fails to properly initialize the variables 'k1' and 'k2'.
+
template<typename A> struct S {
- template<typename B> static int V;
template<typename B> static int V0;
+ template<typename B> static int V1;
};
template struct S<int>;
template<typename A> template<typename B> int S<A>::V0 = 123;
- template<typename A> template<typename B> int S<A>::V<B> = 123;
- int k = S<int>::V<void>;
+ template<typename A> template<typename B> int S<A>::V1<B*> = 123;
+ int k1 = S<int>::V0<void>;
+ int k2 = S<int>::V1<void*>;
}
namespace incomplete_array {
@@ -244,7 +245,7 @@ namespace in_class_template {
// FIXME: These cases should be accepted.
int *use_before_definition = A<int>::x<char>;
- template<typename T> template<typename U> T A<T>::x<U>[sizeof(U)];
+ template<typename T> template<typename U> T A<T>::x[sizeof(U)];
static_assert(sizeof(A<int>::x<char>) == 1, ""); // expected-error {{incomplete}}
template<typename T> template<typename...U> T A<T>::y<tuple<U...> >[] = { U()... };
Modified: cfe/trunk/test/SemaCXX/cxx1y-variable-templates_top_level.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/cxx1y-variable-templates_top_level.cpp?rev=191278&r1=191277&r2=191278&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/cxx1y-variable-templates_top_level.cpp (original)
+++ cfe/trunk/test/SemaCXX/cxx1y-variable-templates_top_level.cpp Mon Sep 23 23:49:23 2013
@@ -315,8 +315,7 @@ namespace explicit_specialization {
namespace diff_type {
// TODO:
- template<typename T> T var = T();
- template<typename T> T* var<T> = new T();
+ template<typename T> T* var = new T();
#ifndef PRECXX11
template<typename T> auto var<T*> = T(); // expected-note {{previous definition is here}}
template<typename T> T var<T*> = T(); // expected-error {{redefinition of 'var' with a different type: 'T' vs 'auto'}}
More information about the cfe-commits
mailing list