From: Douglas Gregor
Date: Fri, 12 Jun 2009 22:08:06 +0000 (+0000)
Subject: Diagnose C++ [temp.class.spec]p9b3, where a class template partial
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6aa75cfbdd473cb8fb2a2261abf7e9d3c8389bca;p=clang
Diagnose C++ [temp.class.spec]p9b3, where a class template partial
specialization's arguments are identical to the implicit template
arguments of the primary template. Typically, this is meant to be a
declaration/definition of the primary template, so we give that
advice.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73259 91177308-0d34-0410-b5e6-96231b3b80d8
---
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 7291d9148b..16d490f09b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -765,6 +765,10 @@ def err_dependent_non_type_arg_in_partial_spec : Error<
def err_dependent_typed_non_type_arg_in_partial_spec : Error<
"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">;
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 2b4713980b..3315952723 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1954,7 +1954,8 @@ public:
bool CheckClassTemplatePartialSpecializationArgs(
TemplateParameterList *TemplateParams,
- const TemplateArgument *TemplateArgs);
+ const TemplateArgument *TemplateArgs,
+ bool &MirrorsPrimaryTemplate);
virtual DeclResult
ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 113ed98eb3..b1a8ef2f7f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2006,22 +2006,68 @@ Sema::CheckClassTemplateSpecializationScope(ClassTemplateDecl *ClassTemplate,
/// \brief Check the non-type template arguments of a class template
/// partial specialization according to C++ [temp.class.spec]p9.
///
+/// \param TemplateParams the template parameters of the primary class
+/// template.
+///
+/// \param TemplateArg the template arguments of the class template
+/// partial specialization.
+///
+/// \param MirrorsPrimaryTemplate will be set true if the class
+/// template partial specialization arguments are identical to the
+/// implicit template arguments of the primary template. This is not
+/// necessarily an error (C++0x), and it is left to the caller to diagnose
+/// this condition when it is an error.
+///
/// \returns true if there was an error, false otherwise.
bool Sema::CheckClassTemplatePartialSpecializationArgs(
TemplateParameterList *TemplateParams,
- const TemplateArgument *TemplateArgs) {
+ const TemplateArgument *TemplateArgs,
+ bool &MirrorsPrimaryTemplate) {
// FIXME: the interface to this function will have to change to
// accommodate variadic templates.
-
+ MirrorsPrimaryTemplate = true;
for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+ // Determine whether the template argument list of the partial
+ // specialization is identical to the implicit argument list of
+ // the primary template. The caller may need to diagnostic this as
+ // an error per C++ [temp.class.spec]p9b3.
+ if (MirrorsPrimaryTemplate) {
+ if (TemplateTypeParmDecl *TTP
+ = dyn_cast(TemplateParams->getParam(I))) {
+ if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) !=
+ Context.getCanonicalType(TemplateArgs[I].getAsType()))
+ MirrorsPrimaryTemplate = false;
+ } else if (TemplateTemplateParmDecl *TTP
+ = dyn_cast(
+ TemplateParams->getParam(I))) {
+ // FIXME: We should settle on either Declaration storage or
+ // Expression storage for template template parameters.
+ TemplateTemplateParmDecl *ArgDecl
+ = dyn_cast_or_null(
+ TemplateArgs[I].getAsDecl());
+ if (!ArgDecl)
+ if (DeclRefExpr *DRE
+ = dyn_cast_or_null(TemplateArgs[I].getAsExpr()))
+ ArgDecl = dyn_cast(DRE->getDecl());
+
+ if (!ArgDecl ||
+ ArgDecl->getIndex() != TTP->getIndex() ||
+ ArgDecl->getDepth() != TTP->getDepth())
+ MirrorsPrimaryTemplate = false;
+ }
+ }
+
NonTypeTemplateParmDecl *Param
= dyn_cast(TemplateParams->getParam(I));
- if (!Param)
+ if (!Param) {
continue;
-
+ }
+
Expr *ArgExpr = TemplateArgs[I].getAsExpr();
- if (!ArgExpr)
+ if (!ArgExpr) {
+ MirrorsPrimaryTemplate = false;
continue;
+ }
// C++ [temp.class.spec]p8:
// A non-type argument is non-specialized if it is the name of a
@@ -2032,8 +2078,15 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
// specialized non-type arguments, so skip any non-specialized
// arguments.
if (DeclRefExpr *DRE = dyn_cast(ArgExpr))
- if (isa(DRE->getDecl()))
+ if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast(DRE->getDecl())) {
+ if (MirrorsPrimaryTemplate &&
+ (Param->getIndex() != NTTP->getIndex() ||
+ Param->getDepth() != NTTP->getDepth()))
+ MirrorsPrimaryTemplate = false;
+
continue;
+ }
// C++ [temp.class.spec]p9:
// Within the argument list of a class template partial
@@ -2060,6 +2113,8 @@ bool Sema::CheckClassTemplatePartialSpecializationArgs(
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
}
+
+ MirrorsPrimaryTemplate = false;
}
return false;
@@ -2179,11 +2234,30 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
// corresponds to these arguments.
llvm::FoldingSetNodeID ID;
if (isPartialSpecialization) {
+ bool MirrorsPrimaryTemplate;
if (CheckClassTemplatePartialSpecializationArgs(
ClassTemplate->getTemplateParameters(),
- ConvertedTemplateArgs.getFlatArgumentList()))
+ ConvertedTemplateArgs.getFlatArgumentList(),
+ MirrorsPrimaryTemplate))
return true;
+ if (MirrorsPrimaryTemplate) {
+ // 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)
+ << (TK == TK_Definition)
+ << CodeModificationHint::CreateRemoval(SourceRange(LAngleLoc,
+ RAngleLoc));
+ return ActOnClassTemplate(S, TagSpec, TK, KWLoc, SS,
+ ClassTemplate->getIdentifier(),
+ TemplateNameLoc,
+ Attr,
+ move(TemplateParameterLists),
+ AS_none);
+ }
+
// FIXME: Template parameter list matters, too
ClassTemplatePartialSpecializationDecl::Profile(ID,
ConvertedTemplateArgs.getFlatArgumentList(),
diff --git a/test/SemaTemplate/temp_class_spec_neg.cpp b/test/SemaTemplate/temp_class_spec_neg.cpp
index 5fd95a7d2b..d303146dce 100644
--- a/test/SemaTemplate/temp_class_spec_neg.cpp
+++ b/test/SemaTemplate/temp_class_spec_neg.cpp
@@ -1,5 +1,4 @@
// RUN: clang-cc -fsyntax-only -verify %s
-
template struct vector;
// C++ [temp.class.spec]p9
@@ -19,10 +18,14 @@ template< int X, int (*array_ptr)[X] > class A2 {}; // expected-note{{here}}
int array[5];
template< int X > class A2 { }; // expected-error{{specializes}}
-// C++ [temp.class.spec]p10
template class TT>
struct Test0;
+// bullet 3
+template class TT>
+struct Test0; // expected-error{{does not specialize}}
+
+// C++ [temp.class.spec]p10
template class TT = ::vector> // expected-error{{default template argument}}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index b2ba8a35df..3a9a7290fc 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -1888,11 +1888,11 @@ welcome!
|
|
|
- |
+ N/A |
|
- 14.5.5.1 [temp.class.spec.match] |
+ 14.5.4.1 [temp.class.spec.match] |
N/A |
N/A |
|
@@ -1900,7 +1900,7 @@ welcome!
|
- 14.5.5.2 [temp.class.order] |
+ 14.5.4.2 [temp.class.order] |
|
|
|