[cfe-commits] r73254 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiateExpr.cpp test/SemaTemplate/temp_class_spec.cpp test/SemaTemplate/temp_class_spec_neg.cpp
Douglas Gregor
dgregor at apple.com
Fri Jun 12 14:21:02 PDT 2009
Author: dgregor
Date: Fri Jun 12 16:21:02 2009
New Revision: 73254
URL: http://llvm.org/viewvc/llvm-project?rev=73254&view=rev
Log:
Diagnose the incorrect use of non-type template arguments for class
template partial specializations.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp
cfe/trunk/test/SemaTemplate/temp_class_spec.cpp
cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=73254&r1=73253&r2=73254&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 12 16:21:02 2009
@@ -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">;
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=73254&r1=73253&r2=73254&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Jun 12 16:21:02 2009
@@ -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,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=73254&r1=73253&r2=73254&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Jun 12 16:21:02 2009
@@ -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(),
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp?rev=73254&r1=73253&r2=73254&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp Fri Jun 12 16:21:02 2009
@@ -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(
Modified: cfe/trunk/test/SemaTemplate/temp_class_spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec.cpp?rev=73254&r1=73253&r2=73254&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec.cpp Fri Jun 12 16:21:02 2009
@@ -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];
Modified: cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp?rev=73254&r1=73253&r2=73254&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec_neg.cpp Fri Jun 12 16:21:02 2009
@@ -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;
More information about the cfe-commits
mailing list