Diagnose the incorrect use of non-type template arguments for class
template partial specializations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73254 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 1a1fdbf..7291d91 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -759,6 +759,12 @@
// C++ Class Template Partial Specialization
def err_default_arg_in_partial_spec : Error<
"default template argument in a class template partial specialization">;
+def err_dependent_non_type_arg_in_partial_spec : Error<
+ "non-type template argument depends on a template parameter of the "
+ "partial specialization">;
+def err_dependent_typed_non_type_arg_in_partial_spec : Error<
+ "non-type template argument specializes a template parameter with "
+ "dependent type %0">;
def unsup_template_partial_spec_ordering : Error<
"partial ordering of class template partial specializations is not yet "
"supported">;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 03ff7a2..2b47139 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1952,6 +1952,10 @@
SourceRange ScopeSpecifierRange,
bool ExplicitInstantiation);
+ bool CheckClassTemplatePartialSpecializationArgs(
+ TemplateParameterList *TemplateParams,
+ const TemplateArgument *TemplateArgs);
+
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 5fb1fb8..113ed98 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2003,6 +2003,68 @@
return false;
}
+/// \brief Check the non-type template arguments of a class template
+/// partial specialization according to C++ [temp.class.spec]p9.
+///
+/// \returns true if there was an error, false otherwise.
+bool Sema::CheckClassTemplatePartialSpecializationArgs(
+ TemplateParameterList *TemplateParams,
+ const TemplateArgument *TemplateArgs) {
+ // FIXME: the interface to this function will have to change to
+ // accommodate variadic templates.
+
+ for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ NonTypeTemplateParmDecl *Param
+ = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I));
+ if (!Param)
+ continue;
+
+ Expr *ArgExpr = TemplateArgs[I].getAsExpr();
+ if (!ArgExpr)
+ continue;
+
+ // C++ [temp.class.spec]p8:
+ // A non-type argument is non-specialized if it is the name of a
+ // non-type parameter. All other non-type arguments are
+ // specialized.
+ //
+ // Below, we check the two conditions that only apply to
+ // specialized non-type arguments, so skip any non-specialized
+ // arguments.
+ if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ArgExpr))
+ if (isa<NonTypeTemplateParmDecl>(DRE->getDecl()))
+ continue;
+
+ // C++ [temp.class.spec]p9:
+ // Within the argument list of a class template partial
+ // specialization, the following restrictions apply:
+ // -- A partially specialized non-type argument expression
+ // shall not involve a template parameter of the partial
+ // specialization except when the argument expression is a
+ // simple identifier.
+ if (ArgExpr->isTypeDependent() || ArgExpr->isValueDependent()) {
+ Diag(ArgExpr->getLocStart(),
+ diag::err_dependent_non_type_arg_in_partial_spec)
+ << ArgExpr->getSourceRange();
+ return true;
+ }
+
+ // -- The type of a template parameter corresponding to a
+ // specialized non-type argument shall not be dependent on a
+ // parameter of the specialization.
+ if (Param->getType()->isDependentType()) {
+ Diag(ArgExpr->getLocStart(),
+ diag::err_dependent_typed_non_type_arg_in_partial_spec)
+ << Param->getType()
+ << ArgExpr->getSourceRange();
+ Diag(Param->getLocation(), diag::note_template_param_here);
+ return true;
+ }
+ }
+
+ return false;
+}
+
Sema::DeclResult
Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
SourceLocation KWLoc,
@@ -2117,6 +2179,11 @@
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
if (isPartialSpecialization) {
+ if (CheckClassTemplatePartialSpecializationArgs(
+ ClassTemplate->getTemplateParameters(),
+ ConvertedTemplateArgs.getFlatArgumentList()))
+ return true;
+
// FIXME: Template parameter list matters, too
ClassTemplatePartialSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
diff --git a/lib/Sema/SemaTemplateInstantiateExpr.cpp b/lib/Sema/SemaTemplateInstantiateExpr.cpp
index fa5fdee..3c67f2a 100644
--- a/lib/Sema/SemaTemplateInstantiateExpr.cpp
+++ b/lib/Sema/SemaTemplateInstantiateExpr.cpp
@@ -112,6 +112,14 @@
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) {
assert(NTTP->getDepth() == 0 && "No nested templates yet");
const TemplateArgument &Arg = TemplateArgs[NTTP->getPosition()];
+
+ // The template argument itself might be an expression, in which
+ // case we just return that expression.
+ if (Arg.getKind() == TemplateArgument::Expression)
+ // FIXME: Clone the expression!
+ return SemaRef.Owned(Arg.getAsExpr());
+
+ assert(Arg.getKind() == TemplateArgument::Integral);
QualType T = Arg.getIntegralType();
if (T->isCharType() || T->isWideCharType())
return SemaRef.Owned(new (SemaRef.Context) CharacterLiteral(
diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp
index 0d83a9b..ce1459b 100644
--- a/test/SemaTemplate/temp_class_spec.cpp
+++ b/test/SemaTemplate/temp_class_spec.cpp
@@ -255,48 +255,3 @@
//int is_nested_value_type_identity2[
// is_nested_value_type_identity<NoValueType>::value? -1 : 1];
-// FIXME: The tests that follow are stress-tests for the substitution
-// of deduced template arguments into the template argument list of a
-// partial specialization. I believe that we'll need this code for
-// substitution into function templates, but note that the examples
-// below are ill-formed and should eventually be removed.
-template<typename T, int N>
-struct is_sizeof_T {
- static const bool value = false;
-};
-
-template<typename T>
-struct is_sizeof_T<T, sizeof(T)> {
- static const bool value = true;
-};
-
-int is_sizeof_T0[is_sizeof_T<int, sizeof(int)>::value? 1 : -1];
-int is_sizeof_T1[is_sizeof_T<int, sizeof(char)>::value? -1 : 1];
-
-template<typename T>
-struct HasStaticOfT {
- static T value;
- static T other_value;
-};
-
-struct DerivedStaticOfInt : HasStaticOfT<int> { };
-
-template<typename X, typename T, T *Ptr>
-struct is_static_int_val {
- static const bool value = false;
-};
-
-template<typename X, typename T>
-struct is_static_int_val<X, T, &X::value> {
- static const bool value = true;
-};
-
-int is_static_int_val0[
- is_static_int_val<HasStaticOfT<int>, int,
- &HasStaticOfT<int>::value>::value ? 1 : -1];
-int is_static_int_val1[
- is_static_int_val<HasStaticOfT<int>, int,
- &HasStaticOfT<int>::other_value>::value ? -1 : 1];
-int is_static_int_val2[
- is_static_int_val<DerivedStaticOfInt, int,
- &HasStaticOfT<int>::value>::value ? 1 : -1];
diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp
index e911434..5fd95a7 100644
--- a/test/SemaTemplate/temp_class_spec_neg.cpp
+++ b/test/SemaTemplate/temp_class_spec_neg.cpp
@@ -2,6 +2,24 @@
template<typename T> struct vector;
+// C++ [temp.class.spec]p9
+
+// bullet 1
+template <int I, int J> struct A {};
+template <int I> struct A<I+5, I*2> {}; // expected-error{{depends on}}
+template <int I, int J> struct B {};
+template <int I> struct B<I, I> {}; //OK
+
+// bullet 2
+template <class T, T t> struct C {}; // expected-note{{declared here}}
+template <class T> struct C<T, 1>; // expected-error{{specializes}}
+template <class T, T* t> struct C<T*, t>; // okay
+
+template< int X, int (*array_ptr)[X] > class A2 {}; // expected-note{{here}}
+int array[5];
+template< int X > class A2<X,&array> { }; // expected-error{{specializes}}
+
+// C++ [temp.class.spec]p10
template<typename T, int N, template<typename X> class TT>
struct Test0;