forked from OSchip/llvm-project
DR1495: A partial specialization is ill-formed if it is not (strictly) more
specialized than the primary template. (Put another way, if we imagine there were a partial specialization matching the primary template, we should never select it if some other partial specialization also matches.) llvm-svn: 290593
This commit is contained in:
parent
625038d5d5
commit
0e617ecdd1
|
@ -4043,6 +4043,10 @@ def err_partial_spec_args_match_primary_template : Error<
|
|||
"%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 err_partial_spec_not_more_specialized_than_primary : Error<
|
||||
"%select{class|variable}0 template partial specialization is not "
|
||||
"more specialized than the primary template">;
|
||||
def note_partial_spec_not_more_specialized_than_primary : Note<"%0">;
|
||||
def warn_partial_specs_not_deducible : Warning<
|
||||
"%select{class|variable}0 template partial specialization contains "
|
||||
"%select{a template parameter|template parameters}1 that cannot be "
|
||||
|
@ -4147,7 +4151,7 @@ def note_function_template_deduction_instantiation_here : Note<
|
|||
"%1">;
|
||||
def note_deduced_template_arg_substitution_here : Note<
|
||||
"during template argument deduction for %select{class|variable}0 template "
|
||||
"partial specialization %1 %2">;
|
||||
"%select{partial specialization |}1%2 %3">;
|
||||
def note_prior_template_arg_substitution : Note<
|
||||
"while substituting prior template arguments into %select{non-type|template}0"
|
||||
" template parameter%1 %2">;
|
||||
|
|
|
@ -6697,10 +6697,16 @@ public:
|
|||
ClassTemplatePartialSpecializationDecl *PS2,
|
||||
SourceLocation Loc);
|
||||
|
||||
bool isMoreSpecializedThanPrimary(ClassTemplatePartialSpecializationDecl *T,
|
||||
sema::TemplateDeductionInfo &Info);
|
||||
|
||||
VarTemplatePartialSpecializationDecl *getMoreSpecializedPartialSpecialization(
|
||||
VarTemplatePartialSpecializationDecl *PS1,
|
||||
VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc);
|
||||
|
||||
bool isMoreSpecializedThanPrimary(VarTemplatePartialSpecializationDecl *T,
|
||||
sema::TemplateDeductionInfo &Info);
|
||||
|
||||
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
|
||||
bool OnlyDeduced,
|
||||
unsigned Depth,
|
||||
|
@ -6752,7 +6758,7 @@ public:
|
|||
/// template argument deduction for either a class template
|
||||
/// partial specialization or a function template. The
|
||||
/// Entity is either a {Class|Var}TemplatePartialSpecializationDecl or
|
||||
/// a FunctionTemplateDecl.
|
||||
/// a TemplateDecl.
|
||||
DeducedTemplateArgumentSubstitution,
|
||||
|
||||
/// We are substituting prior template arguments into a new
|
||||
|
@ -6973,6 +6979,14 @@ public:
|
|||
sema::TemplateDeductionInfo &DeductionInfo,
|
||||
SourceRange InstantiationRange = SourceRange());
|
||||
|
||||
/// \brief Note that we are instantiating as part of template
|
||||
/// argument deduction for a class template declaration.
|
||||
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
TemplateDecl *Template,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
sema::TemplateDeductionInfo &DeductionInfo,
|
||||
SourceRange InstantiationRange = SourceRange());
|
||||
|
||||
/// \brief Note that we are instantiating as part of template
|
||||
/// argument deduction for a class template partial
|
||||
/// specialization.
|
||||
|
|
|
@ -79,6 +79,11 @@ public:
|
|||
assert(HasSFINAEDiagnostic);
|
||||
PD.first = SuppressedDiagnostics.front().first;
|
||||
PD.second.swap(SuppressedDiagnostics.front().second);
|
||||
clearSFINAEDiagnostic();
|
||||
}
|
||||
|
||||
/// \brief Discard any SFINAE diagnostics.
|
||||
void clearSFINAEDiagnostic() {
|
||||
SuppressedDiagnostics.clear();
|
||||
HasSFINAEDiagnostic = false;
|
||||
}
|
||||
|
|
|
@ -2624,6 +2624,36 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) {
|
|||
return TemplateArgs;
|
||||
}
|
||||
|
||||
template<typename PartialSpecDecl>
|
||||
static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) {
|
||||
if (Partial->getDeclContext()->isDependentContext())
|
||||
return;
|
||||
|
||||
// FIXME: Get the TDK from deduction in order to provide better diagnostics
|
||||
// for non-substitution-failure issues?
|
||||
TemplateDeductionInfo Info(Partial->getLocation());
|
||||
if (S.isMoreSpecializedThanPrimary(Partial, Info))
|
||||
return;
|
||||
|
||||
auto *Template = Partial->getSpecializedTemplate();
|
||||
S.Diag(Partial->getLocation(),
|
||||
diag::err_partial_spec_not_more_specialized_than_primary)
|
||||
<< /*variable template*/isa<VarTemplateDecl>(Template);
|
||||
|
||||
if (Info.hasSFINAEDiagnostic()) {
|
||||
PartialDiagnosticAt Diag = {SourceLocation(),
|
||||
PartialDiagnostic::NullDiagnostic()};
|
||||
Info.takeSFINAEDiagnostic(Diag);
|
||||
SmallString<128> SFINAEArgString;
|
||||
Diag.second.EmitToString(S.getDiagnostics(), SFINAEArgString);
|
||||
S.Diag(Diag.first,
|
||||
diag::note_partial_spec_not_more_specialized_than_primary)
|
||||
<< SFINAEArgString;
|
||||
}
|
||||
|
||||
S.Diag(Template->getLocation(), diag::note_template_decl_here);
|
||||
}
|
||||
|
||||
DeclResult Sema::ActOnVarTemplateSpecialization(
|
||||
Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc,
|
||||
TemplateParameterList *TemplateParams, StorageClass SC,
|
||||
|
@ -2749,6 +2779,11 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
|
|||
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
|
||||
PrevPartial->setMemberSpecialization();
|
||||
|
||||
// C++1z [temp.class.spec]p8: (DR1495)
|
||||
// - The specialization shall be more specialized than the primary
|
||||
// template (14.5.5.2).
|
||||
checkMoreSpecializedThanPrimary(*this, Partial);
|
||||
|
||||
// Check that all of the template parameters of the variable template
|
||||
// partial specialization are deducible from the template
|
||||
// arguments. If not, this variable template partial specialization
|
||||
|
@ -5041,7 +5076,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
|
||||
if (CTAK == CTAK_Deduced &&
|
||||
!Context.hasSameType(ParamType.getNonLValueExprType(Context),
|
||||
Arg->getType().getNonLValueExprType(Context))) {
|
||||
Arg->getType())) {
|
||||
// C++ [temp.deduct.type]p17: (DR1770)
|
||||
// If P has a form that contains <i>, and if the type of i differs from
|
||||
// the type of the corresponding template parameter of the template named
|
||||
|
@ -5055,7 +5090,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
// itself, and so strip off references before comparing types. It's
|
||||
// not clear how this is supposed to work for references.
|
||||
Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch)
|
||||
<< Arg->getType().getUnqualifiedType()
|
||||
<< Arg->getType()
|
||||
<< ParamType.getUnqualifiedType();
|
||||
Diag(Param->getLocation(), diag::note_template_param_here);
|
||||
return ExprError();
|
||||
|
@ -6501,6 +6536,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
//
|
||||
// -- The argument list of the specialization shall not be identical
|
||||
// to the implicit argument list of the primary template.
|
||||
//
|
||||
// This rule has since been removed, because it's redundant given DR1495,
|
||||
// but we keep it because it produces better diagnostics and recovery.
|
||||
Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template)
|
||||
<< /*class template*/0 << (TUK == TUK_Definition)
|
||||
<< FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc));
|
||||
|
@ -6543,6 +6581,11 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
|
|||
if (PrevPartial && PrevPartial->getInstantiatedFromMember())
|
||||
PrevPartial->setMemberSpecialization();
|
||||
|
||||
// C++1z [temp.class.spec]p8: (DR1495)
|
||||
// - The specialization shall be more specialized than the primary
|
||||
// template (14.5.5.2).
|
||||
checkMoreSpecializedThanPrimary(*this, Partial);
|
||||
|
||||
// Check that all of the template parameters of the class template
|
||||
// partial specialization are deducible from the template
|
||||
// arguments. If not, this class template partial specialization
|
||||
|
|
|
@ -1972,8 +1972,14 @@ DeduceTemplateArguments(Sema &S,
|
|||
|
||||
/// \brief Determine whether two template arguments are the same.
|
||||
static bool isSameTemplateArg(ASTContext &Context,
|
||||
const TemplateArgument &X,
|
||||
const TemplateArgument &Y) {
|
||||
TemplateArgument X,
|
||||
const TemplateArgument &Y,
|
||||
bool PackExpansionMatchesPack = false) {
|
||||
// If we're checking deduced arguments (X) against original arguments (Y),
|
||||
// we will have flattened packs to non-expansions in X.
|
||||
if (PackExpansionMatchesPack && X.isPackExpansion() && !Y.isPackExpansion())
|
||||
X = X.getPackExpansionPattern();
|
||||
|
||||
if (X.getKind() != Y.getKind())
|
||||
return false;
|
||||
|
||||
|
@ -2016,7 +2022,7 @@ static bool isSameTemplateArg(ASTContext &Context,
|
|||
XPEnd = X.pack_end(),
|
||||
YP = Y.pack_begin();
|
||||
XP != XPEnd; ++XP, ++YP)
|
||||
if (!isSameTemplateArg(Context, *XP, *YP))
|
||||
if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -2400,6 +2406,48 @@ FinishTemplateArgumentDeduction(
|
|||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
/// Complete template argument deduction for a class or variable template,
|
||||
/// when partial ordering against a partial specialization.
|
||||
// FIXME: Factor out duplication with partial specialization version above.
|
||||
Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
|
||||
Sema &S, TemplateDecl *Template, bool PartialOrdering,
|
||||
const TemplateArgumentList &TemplateArgs,
|
||||
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
|
||||
TemplateDeductionInfo &Info) {
|
||||
// Unevaluated SFINAE context.
|
||||
EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated);
|
||||
Sema::SFINAETrap Trap(S);
|
||||
|
||||
Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template));
|
||||
|
||||
// C++ [temp.deduct.type]p2:
|
||||
// [...] or if any template argument remains neither deduced nor
|
||||
// explicitly specified, template argument deduction fails.
|
||||
SmallVector<TemplateArgument, 4> Builder;
|
||||
if (auto Result = ConvertDeducedTemplateArguments(
|
||||
S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder))
|
||||
return Result;
|
||||
|
||||
// Check that we produced the correct argument list.
|
||||
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
|
||||
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
|
||||
TemplateArgument InstArg = Builder[I];
|
||||
if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg,
|
||||
/*PackExpansionMatchesPack*/true)) {
|
||||
Info.Param = makeTemplateParameter(TemplateParams->getParam(I));
|
||||
Info.FirstArg = TemplateArgs[I];
|
||||
Info.SecondArg = InstArg;
|
||||
return Sema::TDK_NonDeducedMismatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (Trap.hasErrorOccurred())
|
||||
return Sema::TDK_SubstitutionFailure;
|
||||
|
||||
return Sema::TDK_Success;
|
||||
}
|
||||
|
||||
|
||||
/// \brief Perform template argument deduction to determine whether
|
||||
/// the given template arguments match the given class template
|
||||
/// partial specialization per C++ [temp.class.spec.match].
|
||||
|
@ -4535,14 +4583,13 @@ UnresolvedSetIterator Sema::getMostSpecialized(
|
|||
/// specialized than another, P2.
|
||||
///
|
||||
/// \tparam PartialSpecializationDecl The kind of P2, which must be a
|
||||
/// {Class,Var}TemplatePartialSpecializationDecl.
|
||||
/// {Class,Var}Template{PartialSpecialization,}Decl.
|
||||
/// \param T1 The injected-class-name of P1 (faked for a variable template).
|
||||
/// \param T2 The injected-class-name of P2 (faked for a variable template).
|
||||
/// \param Loc The location at which the comparison is required.
|
||||
template<typename PartialSpecializationDecl>
|
||||
static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
|
||||
PartialSpecializationDecl *P2,
|
||||
SourceLocation Loc) {
|
||||
TemplateDeductionInfo &Info) {
|
||||
// C++ [temp.class.order]p1:
|
||||
// For two class template partial specializations, the first is at least as
|
||||
// specialized as the second if, given the following rewrite to two
|
||||
|
@ -4568,7 +4615,6 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
|
|||
// template partial specialization's template arguments, for
|
||||
// example.
|
||||
SmallVector<DeducedTemplateArgument, 4> Deduced;
|
||||
TemplateDeductionInfo Info(Loc);
|
||||
|
||||
// Determine whether P1 is at least as specialized as P2.
|
||||
Deduced.resize(P2->getTemplateParameters()->size());
|
||||
|
@ -4579,7 +4625,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2,
|
|||
|
||||
SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
|
||||
Deduced.end());
|
||||
Sema::InstantiatingTemplate Inst(S, Loc, P2, DeducedArgs, Info);
|
||||
Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs,
|
||||
Info);
|
||||
auto *TST1 = T1->castAs<TemplateSpecializationType>();
|
||||
if (FinishTemplateArgumentDeduction(
|
||||
S, P2, /*PartialOrdering=*/true,
|
||||
|
@ -4609,8 +4656,9 @@ Sema::getMoreSpecializedPartialSpecialization(
|
|||
QualType PT1 = PS1->getInjectedSpecializationType();
|
||||
QualType PT2 = PS2->getInjectedSpecializationType();
|
||||
|
||||
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc);
|
||||
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc);
|
||||
TemplateDeductionInfo Info(Loc);
|
||||
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
|
||||
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
|
||||
|
||||
if (Better1 == Better2)
|
||||
return nullptr;
|
||||
|
@ -4618,6 +4666,20 @@ Sema::getMoreSpecializedPartialSpecialization(
|
|||
return Better1 ? PS1 : PS2;
|
||||
}
|
||||
|
||||
bool Sema::isMoreSpecializedThanPrimary(
|
||||
ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
|
||||
ClassTemplateDecl *Primary = Spec->getSpecializedTemplate();
|
||||
QualType PrimaryT = Primary->getInjectedClassNameSpecialization();
|
||||
QualType PartialT = Spec->getInjectedSpecializationType();
|
||||
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
|
||||
return false;
|
||||
if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
|
||||
Info.clearSFINAEDiagnostic();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VarTemplatePartialSpecializationDecl *
|
||||
Sema::getMoreSpecializedPartialSpecialization(
|
||||
VarTemplatePartialSpecializationDecl *PS1,
|
||||
|
@ -4634,8 +4696,9 @@ Sema::getMoreSpecializedPartialSpecialization(
|
|||
QualType PT2 = Context.getTemplateSpecializationType(
|
||||
CanonTemplate, PS2->getTemplateArgs().asArray());
|
||||
|
||||
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Loc);
|
||||
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Loc);
|
||||
TemplateDeductionInfo Info(Loc);
|
||||
bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info);
|
||||
bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info);
|
||||
|
||||
if (Better1 == Better2)
|
||||
return nullptr;
|
||||
|
@ -4643,6 +4706,30 @@ Sema::getMoreSpecializedPartialSpecialization(
|
|||
return Better1 ? PS1 : PS2;
|
||||
}
|
||||
|
||||
bool Sema::isMoreSpecializedThanPrimary(
|
||||
VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
|
||||
TemplateDecl *Primary = Spec->getSpecializedTemplate();
|
||||
// FIXME: Cache the injected template arguments rather than recomputing
|
||||
// them for each partial specialization.
|
||||
SmallVector<TemplateArgument, 8> PrimaryArgs;
|
||||
Context.getInjectedTemplateArgs(Primary->getTemplateParameters(),
|
||||
PrimaryArgs);
|
||||
|
||||
TemplateName CanonTemplate =
|
||||
Context.getCanonicalTemplateName(TemplateName(Primary));
|
||||
QualType PrimaryT = Context.getTemplateSpecializationType(
|
||||
CanonTemplate, PrimaryArgs);
|
||||
QualType PartialT = Context.getTemplateSpecializationType(
|
||||
CanonTemplate, Spec->getTemplateArgs().asArray());
|
||||
if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info))
|
||||
return false;
|
||||
if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) {
|
||||
Info.clearSFINAEDiagnostic();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
MarkUsedTemplateParameters(ASTContext &Ctx,
|
||||
const TemplateArgument &TemplateArg,
|
||||
|
|
|
@ -277,6 +277,17 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(
|
|||
Kind == ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution);
|
||||
}
|
||||
|
||||
Sema::InstantiatingTemplate::InstantiatingTemplate(
|
||||
Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
TemplateDecl *Template,
|
||||
ArrayRef<TemplateArgument> TemplateArgs,
|
||||
sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange)
|
||||
: InstantiatingTemplate(
|
||||
SemaRef,
|
||||
ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution,
|
||||
PointOfInstantiation, InstantiationRange, Template, nullptr,
|
||||
TemplateArgs, &DeductionInfo) {}
|
||||
|
||||
Sema::InstantiatingTemplate::InstantiatingTemplate(
|
||||
Sema &SemaRef, SourceLocation PointOfInstantiation,
|
||||
ClassTemplatePartialSpecializationDecl *PartialSpec,
|
||||
|
@ -497,8 +508,12 @@ void Sema::PrintInstantiationStack() {
|
|||
} else {
|
||||
bool IsVar = isa<VarTemplateDecl>(Active->Entity) ||
|
||||
isa<VarTemplateSpecializationDecl>(Active->Entity);
|
||||
bool IsTemplate = false;
|
||||
TemplateParameterList *Params;
|
||||
if (auto *D = dyn_cast<ClassTemplatePartialSpecializationDecl>(
|
||||
if (auto *D = dyn_cast<TemplateDecl>(Active->Entity)) {
|
||||
IsTemplate = true;
|
||||
Params = D->getTemplateParameters();
|
||||
} else if (auto *D = dyn_cast<ClassTemplatePartialSpecializationDecl>(
|
||||
Active->Entity)) {
|
||||
Params = D->getTemplateParameters();
|
||||
} else if (auto *D = dyn_cast<VarTemplatePartialSpecializationDecl>(
|
||||
|
@ -510,7 +525,7 @@ void Sema::PrintInstantiationStack() {
|
|||
|
||||
Diags.Report(Active->PointOfInstantiation,
|
||||
diag::note_deduced_template_arg_substitution_here)
|
||||
<< IsVar << cast<NamedDecl>(Active->Entity)
|
||||
<< IsVar << IsTemplate << cast<NamedDecl>(Active->Entity)
|
||||
<< getTemplateArgumentBindingsText(Params, Active->TemplateArgs,
|
||||
Active->NumTemplateArgs)
|
||||
<< Active->InstantiationRange;
|
||||
|
|
|
@ -342,4 +342,32 @@ namespace dr1490 { // dr1490: 3.7 c++11
|
|||
char s[4]{"abc"}; // Ok
|
||||
std::initializer_list<char>{"abc"}; // expected-error {{expected unqualified-id}}}
|
||||
} // dr190
|
||||
|
||||
namespace dr1495 { // dr1495: 4.0
|
||||
// Deduction succeeds in both directions.
|
||||
template<typename T, typename U> struct A {}; // expected-note {{template is declared here}}
|
||||
template<typename T, typename U> struct A<U, T> {}; // expected-error {{class template partial specialization is not more specialized}}
|
||||
|
||||
// Primary template is more specialized.
|
||||
template<typename, typename...> struct B {}; // expected-note {{template is declared here}}
|
||||
template<typename ...Ts> struct B<Ts...> {}; // expected-error {{not more specialized}}
|
||||
|
||||
// Deduction fails in both directions.
|
||||
template<int, typename, typename ...> struct C {}; // expected-note {{template is declared here}}
|
||||
template<typename ...Ts> struct C<0, Ts...> {}; // expected-error {{not more specialized}}
|
||||
|
||||
#if __cplusplus >= 201402L
|
||||
// Deduction succeeds in both directions.
|
||||
template<typename T, typename U> int a; // expected-note {{template is declared here}}
|
||||
template<typename T, typename U> int a<U, T>; // expected-error {{variable template partial specialization is not more specialized}}
|
||||
|
||||
// Primary template is more specialized.
|
||||
template<typename, typename...> int b; // expected-note {{template is declared here}}
|
||||
template<typename ...Ts> int b<Ts...>; // expected-error {{not more specialized}}
|
||||
|
||||
// Deduction fails in both directions.
|
||||
template<int, typename, typename ...> int c; // expected-note {{template is declared here}}
|
||||
template<typename ...Ts> int c<0, Ts...>; // expected-error {{not more specialized}}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -108,10 +108,10 @@ namespace PR9021b {
|
|||
|
||||
namespace PartialSpecialization {
|
||||
template<typename T, typename U, typename V = U>
|
||||
struct X0; // expected-note{{template is declared here}}
|
||||
struct X0; // expected-note 2{{template is declared here}}
|
||||
|
||||
template<typename ...Ts>
|
||||
struct X0<Ts...> {
|
||||
struct X0<Ts...> { // expected-error {{class template partial specialization is not more specialized than the primary template}}
|
||||
};
|
||||
|
||||
X0<int> x0i; // expected-error{{too few template arguments for class template 'X0'}}
|
||||
|
|
|
@ -167,10 +167,16 @@ namespace PR16519 {
|
|||
// expected-warning@-2 {{variadic templates are a C++11 extension}}
|
||||
#endif
|
||||
|
||||
template<typename T, T ...N, T ...Extra> struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> {
|
||||
// Note that the following seemingly-equivalent template parameter list is
|
||||
// not OK; it would result in a partial specialization that is not more
|
||||
// specialized than the primary template. (See NTTPTypeVsPartialOrder below.)
|
||||
//
|
||||
// template<typename T, T ...N, T ...Extra>
|
||||
template<typename T, T ...N, typename integer_sequence<T, N...>::value_type ...Extra>
|
||||
#if __cplusplus <= 199711L
|
||||
// expected-warning@-2 2 {{variadic templates are a C++11 extension}}
|
||||
// expected-warning@-2 2{{variadic templates are a C++11 extension}}
|
||||
#endif
|
||||
struct __make_integer_sequence_impl<integer_sequence<T, N...>, Extra...> {
|
||||
typedef integer_sequence<T, N..., sizeof...(N) + N..., Extra...> type;
|
||||
};
|
||||
|
||||
|
@ -193,6 +199,25 @@ namespace PR16519 {
|
|||
#endif
|
||||
}
|
||||
|
||||
namespace NTTPTypeVsPartialOrder {
|
||||
struct X { typedef int value_type; };
|
||||
template<typename T> struct Y { typedef T value_type; };
|
||||
|
||||
template<typename T, typename T::value_type N> struct A; // expected-note {{template}}
|
||||
template<int N> struct A<X, N> {};
|
||||
template<typename T, T N> struct A<Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}}
|
||||
A<X, 0> ax;
|
||||
A<Y<int>, 0> ay;
|
||||
|
||||
|
||||
template<int, typename T, typename T::value_type> struct B; // expected-note {{template}}
|
||||
template<typename T, typename T::value_type N> struct B<0, T, N>; // expected-note {{matches}}
|
||||
template<int N> struct B<0, X, N> {};
|
||||
template<typename T, T N> struct B<0, Y<T>, N> {}; // expected-error {{not more specialized}} expected-note {{'T' vs 'typename Y<type-parameter-0-0>::value_type'}} expected-note {{matches}}
|
||||
B<0, X, 0> bx;
|
||||
B<0, Y<int>, 0> by; // expected-error {{ambiguous}}
|
||||
}
|
||||
|
||||
namespace DefaultArgVsPartialSpec {
|
||||
// Check that the diagnostic points at the partial specialization, not just at
|
||||
// the default argument.
|
||||
|
|
|
@ -367,11 +367,11 @@ namespace PR17696 {
|
|||
|
||||
namespace partial_order_different_types {
|
||||
// These are unordered because the type of the final argument doesn't match.
|
||||
// FIXME: The second partial specialization should actually be rejected
|
||||
// because it's not more specialized than the primary template.
|
||||
template<int, int, typename T, typename, T> struct A;
|
||||
template<int, int, typename T, typename, T> struct A; // expected-note {{here}}
|
||||
template<int N, typename T, typename U, T V> struct A<0, N, T, U, V> {}; // expected-note {{matches}}
|
||||
template<typename T, typename U, U V> struct A<0, 0, T, U, V> {}; // expected-note {{matches}}
|
||||
// expected-error@-1 {{not more specialized than the primary}}
|
||||
// expected-note@-2 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('U' vs 'type-parameter-0-0')}}
|
||||
A<0, 0, int, int, 0> a; // expected-error {{ambiguous partial specializations}}
|
||||
}
|
||||
|
||||
|
@ -389,18 +389,22 @@ namespace partial_order_references {
|
|||
int N;
|
||||
A<0, 0, N> a;
|
||||
|
||||
// FIXME: These should all be rejected as they are not more specialized than
|
||||
// the primary template (they can never be used due to the type mismatch).
|
||||
template<int, int &R> struct B; // expected-note {{template}}
|
||||
template<int, int &R> struct B; // expected-note 2{{template}}
|
||||
template<const int &R> struct B<0, R> {};
|
||||
// expected-error@-1 {{not more specialized than the primary}}
|
||||
// expected-note@-2 {{'const int' vs 'int &'}}
|
||||
B<0, N> b; // expected-error {{undefined}}
|
||||
|
||||
template<int, const int &R> struct C; // expected-note {{template}}
|
||||
template<int, const int &R> struct C; // expected-note 2{{template}}
|
||||
template<int &R> struct C<0, R> {};
|
||||
// expected-error@-1 {{not more specialized than the primary}}
|
||||
// expected-note@-2 {{'int' vs 'const int &'}}
|
||||
C<0, N> c; // expected-error {{undefined}}
|
||||
|
||||
template<int, const int &R> struct D; // expected-note {{template}}
|
||||
template<int, const int &R> struct D; // expected-note 2{{template}}
|
||||
template<int N> struct D<0, N> {};
|
||||
// expected-error@-1 {{not more specialized than the primary}}
|
||||
// expected-note@-2 {{'int' vs 'const int &'}}
|
||||
extern const int K = 5;
|
||||
D<0, K> d; // expected-error {{undefined}}
|
||||
}
|
||||
|
|
|
@ -4195,7 +4195,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#692">692</a></td>
|
||||
<td>C++11</td>
|
||||
<td>Partial ordering of variadic class template partial specializations</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="none" align="center">No</td>
|
||||
</tr>
|
||||
<tr id="693">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#693">693</a></td>
|
||||
|
@ -8785,7 +8785,7 @@ and <I>POD class</I></td>
|
|||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1495">1495</a></td>
|
||||
<td>CD3</td>
|
||||
<td>Partial specialization of variadic class template</td>
|
||||
<td class="none" align="center">Unknown</td>
|
||||
<td class="svn" align="center">SVN</td>
|
||||
</tr>
|
||||
<tr id="1496">
|
||||
<td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1496">1496</a></td>
|
||||
|
|
Loading…
Reference in New Issue