forked from OSchip/llvm-project
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. llvm-svn: 73259
This commit is contained in:
parent
c59a7cb8cc
commit
09a3023e65
|
@ -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">;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<TemplateTypeParmDecl>(TemplateParams->getParam(I))) {
|
||||
if (Context.getCanonicalType(Context.getTypeDeclType(TTP)) !=
|
||||
Context.getCanonicalType(TemplateArgs[I].getAsType()))
|
||||
MirrorsPrimaryTemplate = false;
|
||||
} else if (TemplateTemplateParmDecl *TTP
|
||||
= dyn_cast<TemplateTemplateParmDecl>(
|
||||
TemplateParams->getParam(I))) {
|
||||
// FIXME: We should settle on either Declaration storage or
|
||||
// Expression storage for template template parameters.
|
||||
TemplateTemplateParmDecl *ArgDecl
|
||||
= dyn_cast_or_null<TemplateTemplateParmDecl>(
|
||||
TemplateArgs[I].getAsDecl());
|
||||
if (!ArgDecl)
|
||||
if (DeclRefExpr *DRE
|
||||
= dyn_cast_or_null<DeclRefExpr>(TemplateArgs[I].getAsExpr()))
|
||||
ArgDecl = dyn_cast<TemplateTemplateParmDecl>(DRE->getDecl());
|
||||
|
||||
if (!ArgDecl ||
|
||||
ArgDecl->getIndex() != TTP->getIndex() ||
|
||||
ArgDecl->getDepth() != TTP->getDepth())
|
||||
MirrorsPrimaryTemplate = false;
|
||||
}
|
||||
}
|
||||
|
||||
NonTypeTemplateParmDecl *Param
|
||||
= dyn_cast<NonTypeTemplateParmDecl>(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<DeclRefExpr>(ArgExpr))
|
||||
if (isa<NonTypeTemplateParmDecl>(DRE->getDecl()))
|
||||
if (NonTypeTemplateParmDecl *NTTP
|
||||
= dyn_cast<NonTypeTemplateParmDecl>(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(),
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
template<typename T> 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<X,&array> { }; // expected-error{{specializes}}
|
||||
|
||||
// C++ [temp.class.spec]p10
|
||||
template<typename T, int N, template<typename X> class TT>
|
||||
struct Test0;
|
||||
|
||||
// bullet 3
|
||||
template<typename T, int N, template<typename X> class TT>
|
||||
struct Test0<T, N, TT>; // expected-error{{does not specialize}}
|
||||
|
||||
// C++ [temp.class.spec]p10
|
||||
template<typename T = int, // expected-error{{default template argument}}
|
||||
int N = 17, // expected-error{{default template argument}}
|
||||
template<typename X> class TT = ::vector> // expected-error{{default template argument}}
|
||||
|
|
|
@ -1888,11 +1888,11 @@ welcome!</p>
|
|||
<td class="complete" align="center"></td>
|
||||
<td class="complete" align="center"></td>
|
||||
<td class="medium" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="na" align="center">N/A</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 14.5.5.1 [temp.class.spec.match]</td>
|
||||
<td> 14.5.4.1 [temp.class.spec.match]</td>
|
||||
<td class="na" align="center">N/A</td>
|
||||
<td class="na" align="center">N/A</td>
|
||||
<td class="medium" align="center"></td>
|
||||
|
@ -1900,7 +1900,7 @@ welcome!</p>
|
|||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> 14.5.5.2 [temp.class.order]</td>
|
||||
<td> 14.5.4.2 [temp.class.order]</td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
<td class="broken" align="center"></td>
|
||||
|
|
Loading…
Reference in New Issue