[clang] bdd46cc - Revert "[clang] CWG2398: improve overload resolution backwards compat (#107350)"
Mikhail Goncharov via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 11 05:48:00 PDT 2024
Author: Mikhail Goncharov
Date: 2024-10-11T14:47:21+02:00
New Revision: bdd46cc6b74eeed14936f1373bbb6446e09979fe
URL: https://github.com/llvm/llvm-project/commit/bdd46cc6b74eeed14936f1373bbb6446e09979fe
DIFF: https://github.com/llvm/llvm-project/commit/bdd46cc6b74eeed14936f1373bbb6446e09979fe.diff
LOG: Revert "[clang] CWG2398: improve overload resolution backwards compat (#107350)"
See discussion in https://github.com/llvm/llvm-project/pull/111711
This reverts commit 224519b08945637a85e9798c78286643288f7b77.
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/include/clang/Sema/TemplateDeduction.h
clang/lib/Sema/SemaLookup.cpp
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/test/SemaTemplate/cwg2398.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index df165b91252505..00376ce2a6008b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -207,8 +207,7 @@ Resolutions to C++ Defect Reports
(`CWG2351: void{} <https://cplusplus.github.io/CWG/issues/2351.html>`_).
- Clang now has improved resolution to CWG2398, allowing class templates to have
- default arguments deduced when partial ordering, and better backwards compatibility
- in overload resolution.
+ default arguments deduced when partial ordering.
- Clang now allows comparing unequal object pointers that have been cast to ``void *``
in constant expressions. These comparisons always worked in non-constant expressions.
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 66b0846f286a81..49c593bf88c989 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11638,8 +11638,7 @@ class Sema final : public SemaBase {
SourceLocation RAngleLoc, unsigned ArgumentPackIndex,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
- CheckTemplateArgumentKind CTAK,
- bool *MatchedPackOnParmToNonPackOnArg);
+ CheckTemplateArgumentKind CTAK);
/// Check that the given template arguments can be provided to
/// the given template, converting the arguments along the way.
@@ -11686,8 +11685,7 @@ class Sema final : public SemaBase {
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions = true,
- bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false,
- bool *MatchedPackOnParmToNonPackOnArg = nullptr);
+ bool *ConstraintsNotSatisfied = nullptr, bool PartialOrderingTTP = false);
bool CheckTemplateTypeArgument(
TemplateTypeParmDecl *Param, TemplateArgumentLoc &Arg,
@@ -11721,8 +11719,7 @@ class Sema final : public SemaBase {
/// It returns true if an error occurred, and false otherwise.
bool CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
TemplateParameterList *Params,
- TemplateArgumentLoc &Arg, bool IsDeduced,
- bool *MatchedPackOnParmToNonPackOnArg);
+ TemplateArgumentLoc &Arg, bool IsDeduced);
void NoteTemplateLocation(const NamedDecl &Decl,
std::optional<SourceRange> ParamRange = {});
@@ -12423,7 +12420,7 @@ class Sema final : public SemaBase {
bool isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *PParam, TemplateDecl *PArg, TemplateDecl *AArg,
const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
- bool IsDeduced, bool *MatchedPackOnParmToNonPackOnArg);
+ bool IsDeduced);
/// Mark which template parameters are used in a given expression.
///
@@ -13422,8 +13419,7 @@ class Sema final : public SemaBase {
bool InstantiateClassTemplateSpecialization(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- TemplateSpecializationKind TSK, bool Complain = true,
- bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false);
+ TemplateSpecializationKind TSK, bool Complain = true);
/// Instantiates the definitions of all of the member
/// of the given class, which is an instantiation of a class template
diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h
index 9c12eef5c42a06..28b014fd84e4b3 100644
--- a/clang/include/clang/Sema/TemplateDeduction.h
+++ b/clang/include/clang/Sema/TemplateDeduction.h
@@ -51,11 +51,6 @@ class TemplateDeductionInfo {
/// Have we suppressed an error during deduction?
bool HasSFINAEDiagnostic = false;
- /// Have we matched any packs on the parameter side, versus any non-packs on
- /// the argument side, in a context where the opposite matching is also
- /// allowed?
- bool MatchedPackOnParmToNonPackOnArg = false;
-
/// The template parameter depth for which we're performing deduction.
unsigned DeducedDepth;
@@ -92,14 +87,6 @@ class TemplateDeductionInfo {
return DeducedDepth;
}
- bool hasMatchedPackOnParmToNonPackOnArg() const {
- return MatchedPackOnParmToNonPackOnArg;
- }
-
- void setMatchedPackOnParmToNonPackOnArg() {
- MatchedPackOnParmToNonPackOnArg = true;
- }
-
/// Get the number of explicitly-specified arguments.
unsigned getNumExplicitArgs() const {
return ExplicitArgs;
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 31422c213ac249..f3f62474d06441 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3666,8 +3666,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
TemplateArgumentLoc Arg(TemplateArgument(StringLit), StringLit);
if (CheckTemplateArgument(
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
- 0, SugaredChecked, CanonicalChecked, CTAK_Specified,
- /*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
+ 0, SugaredChecked, CanonicalChecked, CTAK_Specified) ||
Trap.hasErrorOccurred())
IsTemplate = false;
}
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4f13669c2490c0..226c1172a059d4 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5179,7 +5179,7 @@ bool Sema::CheckTemplateArgument(
unsigned ArgumentPackIndex,
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
- CheckTemplateArgumentKind CTAK, bool *MatchedPackOnParmToNonPackOnArg) {
+ CheckTemplateArgumentKind CTAK) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5395,8 +5395,7 @@ bool Sema::CheckTemplateArgument(
case TemplateArgument::Template:
case TemplateArgument::TemplateExpansion:
if (CheckTemplateTemplateArgument(TempParm, Params, Arg,
- /*IsDeduced=*/CTAK != CTAK_Specified,
- MatchedPackOnParmToNonPackOnArg))
+ /*IsDeduced=*/CTAK != CTAK_Specified))
return true;
SugaredConverted.push_back(Arg.getArgument());
@@ -5470,7 +5469,7 @@ bool Sema::CheckTemplateArgumentList(
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied,
- bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) {
+ bool PartialOrderingTTP) {
if (ConstraintsNotSatisfied)
*ConstraintsNotSatisfied = false;
@@ -5546,10 +5545,10 @@ bool Sema::CheckTemplateArgumentList(
if (ArgIdx < NumArgs) {
// Check the template argument we were given.
- if (CheckTemplateArgument(
- *Param, NewArgs[ArgIdx], Template, TemplateLoc, RAngleLoc,
- SugaredArgumentPack.size(), SugaredConverted, CanonicalConverted,
- CTAK_Specified, MatchedPackOnParmToNonPackOnArg))
+ if (CheckTemplateArgument(*Param, NewArgs[ArgIdx], Template, TemplateLoc,
+ RAngleLoc, SugaredArgumentPack.size(),
+ SugaredConverted, CanonicalConverted,
+ CTAK_Specified))
return true;
CanonicalConverted.back().setIsDefaulted(
@@ -5707,8 +5706,7 @@ bool Sema::CheckTemplateArgumentList(
// Check the default template argument.
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
SugaredConverted, CanonicalConverted,
- CTAK_Specified,
- /*MatchedPackOnParmToNonPackOnArg=*/nullptr))
+ CTAK_Specified))
return true;
SugaredConverted.back().setIsDefaulted(true);
@@ -7291,10 +7289,10 @@ static void DiagnoseTemplateParameterListArityMismatch(
Sema &S, TemplateParameterList *New, TemplateParameterList *Old,
Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc);
-bool Sema::CheckTemplateTemplateArgument(
- TemplateTemplateParmDecl *Param, TemplateParameterList *Params,
- TemplateArgumentLoc &Arg, bool IsDeduced,
- bool *MatchedPackOnParmToNonPackOnArg) {
+bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param,
+ TemplateParameterList *Params,
+ TemplateArgumentLoc &Arg,
+ bool IsDeduced) {
TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern();
auto [Template, DefaultArgs] = Name.getTemplateDeclAndDefaultArgs();
if (!Template) {
@@ -7338,8 +7336,7 @@ bool Sema::CheckTemplateTemplateArgument(
// A template-argument matches a template template-parameter P when P
// is at least as specialized as the template-argument A.
if (!isTemplateTemplateParameterAtLeastAsSpecializedAs(
- Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced,
- MatchedPackOnParmToNonPackOnArg))
+ Params, Param, Template, DefaultArgs, Arg.getLocation(), IsDeduced))
return true;
// P2113
// C++20[temp.func.order]p2
@@ -9757,14 +9754,11 @@ DeclResult Sema::ActOnExplicitInstantiation(
// Check that the template argument list is well-formed for this
// template.
- bool PrimaryHasMatchedPackOnParmToNonPackOnArg = false;
SmallVector<TemplateArgument, 4> SugaredConverted, CanonicalConverted;
- if (CheckTemplateArgumentList(
- ClassTemplate, TemplateNameLoc, TemplateArgs,
- /*DefaultArgs=*/{}, false, SugaredConverted, CanonicalConverted,
- /*UpdateArgsWithConversions=*/true,
- /*ConstraintsNotSatisfied=*/nullptr, /*PartialOrderingTTP=*/false,
- &PrimaryHasMatchedPackOnParmToNonPackOnArg))
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, TemplateArgs,
+ /*DefaultArgs=*/{}, false, SugaredConverted,
+ CanonicalConverted,
+ /*UpdateArgsWithConversions=*/true))
return true;
// Find the class template specialization declaration that
@@ -9885,9 +9879,7 @@ DeclResult Sema::ActOnExplicitInstantiation(
= cast_or_null<ClassTemplateSpecializationDecl>(
Specialization->getDefinition());
if (!Def)
- InstantiateClassTemplateSpecialization(
- TemplateNameLoc, Specialization, TSK,
- /*Complain=*/true, PrimaryHasMatchedPackOnParmToNonPackOnArg);
+ InstantiateClassTemplateSpecialization(TemplateNameLoc, Specialization, TSK);
else if (TSK == TSK_ExplicitInstantiationDefinition) {
MarkVTableUsed(TemplateNameLoc, Specialization, true);
Specialization->setPointOfInstantiation(Def->getPointOfInstantiation());
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 48a39a90f72a8b..03ff8145e3b4ac 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2767,12 +2767,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
for (; hasTemplateArgumentForDeduction(As, ArgIdx) &&
PackScope.hasNextElement();
++ArgIdx) {
- if (!As[ArgIdx].isPackExpansion()) {
- if (!FoldPackParameter)
- return TemplateDeductionResult::MiscellaneousDeductionFailure;
- if (FoldPackArgument)
- Info.setMatchedPackOnParmToNonPackOnArg();
- }
+ if (!FoldPackParameter && !As[ArgIdx].isPackExpansion())
+ return TemplateDeductionResult::MiscellaneousDeductionFailure;
// Deduce template arguments from the pattern.
if (auto Result = DeduceTemplateArguments(
S, TemplateParams, Pattern, As[ArgIdx], Info, PartialOrdering,
@@ -2966,20 +2962,15 @@ static bool ConvertDeducedTemplateArgument(
TemplateArgumentLoc ArgLoc = S.getTrivialTemplateArgumentLoc(
Arg, QualType(), Info.getLocation(), Param);
- bool MatchedPackOnParmToNonPackOnArg = false;
// Check the template argument, converting it as necessary.
- auto Res = S.CheckTemplateArgument(
+ return S.CheckTemplateArgument(
Param, ArgLoc, Template, Template->getLocation(),
Template->getSourceRange().getEnd(), ArgumentPackIndex, SugaredOutput,
CanonicalOutput,
IsDeduced
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
- : Sema::CTAK_Specified,
- &MatchedPackOnParmToNonPackOnArg);
- if (MatchedPackOnParmToNonPackOnArg)
- Info.setMatchedPackOnParmToNonPackOnArg();
- return Res;
+ : Sema::CTAK_Specified);
};
if (Arg.getKind() == TemplateArgument::Pack) {
@@ -3174,8 +3165,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
// Check whether we can actually use the default argument.
if (S.CheckTemplateArgument(
Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
- 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified,
- /*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
+ 0, SugaredBuilder, CanonicalBuilder, Sema::CTAK_Specified)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
@@ -3324,20 +3314,16 @@ FinishTemplateArgumentDeduction(
return TemplateDeductionResult::SubstitutionFailure;
}
- bool MatchedPackOnParmToNonPackOnArg = false;
bool ConstraintsNotSatisfied;
SmallVector<TemplateArgument, 4> SugaredConvertedInstArgs,
CanonicalConvertedInstArgs;
if (S.CheckTemplateArgumentList(
Template, Partial->getLocation(), InstArgs, /*DefaultArgs=*/{}, false,
SugaredConvertedInstArgs, CanonicalConvertedInstArgs,
- /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied,
- /*PartialOrderingTTP=*/false, &MatchedPackOnParmToNonPackOnArg))
+ /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied))
return ConstraintsNotSatisfied
? TemplateDeductionResult::ConstraintsNotSatisfied
: TemplateDeductionResult::SubstitutionFailure;
- if (MatchedPackOnParmToNonPackOnArg)
- Info.setMatchedPackOnParmToNonPackOnArg();
TemplateParameterList *TemplateParams = Template->getTemplateParameters();
for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) {
@@ -6479,8 +6465,8 @@ bool Sema::isMoreSpecializedThanPrimary(
bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
TemplateParameterList *P, TemplateDecl *PArg, TemplateDecl *AArg,
- const DefaultArguments &DefaultArgs, SourceLocation ArgLoc, bool IsDeduced,
- bool *MatchedPackOnParmToNonPackOnArg) {
+ const DefaultArguments &DefaultArgs, SourceLocation ArgLoc,
+ bool IsDeduced) {
// C++1z [temp.arg.template]p4: (DR 150)
// A template template-parameter P is at least as specialized as a
// template template-argument A if, given the following rewrite to two
@@ -6532,11 +6518,11 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
// If the rewrite produces an invalid type, then P is not at least as
// specialized as A.
SmallVector<TemplateArgument, 4> CanonicalPArgs;
- if (CheckTemplateArgumentList(
- AArg, ArgLoc, PArgList, DefaultArgs, false, PArgs, CanonicalPArgs,
- /*UpdateArgsWithConversions=*/true,
- /*ConstraintsNotSatisfied=*/nullptr,
- /*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg))
+ if (CheckTemplateArgumentList(AArg, ArgLoc, PArgList, DefaultArgs, false,
+ PArgs, CanonicalPArgs,
+ /*UpdateArgsWithConversions=*/true,
+ /*ConstraintsNotSatisfied=*/nullptr,
+ /*PartialOrderingTTP=*/true))
return false;
}
@@ -6562,9 +6548,6 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs(
IsDeduced ? PackFold::ArgumentToParameter : PackFold::Both,
/*HasDeducedAnyParam=*/nullptr)) {
case clang::TemplateDeductionResult::Success:
- if (MatchedPackOnParmToNonPackOnArg &&
- Info.hasMatchedPackOnParmToNonPackOnArg())
- *MatchedPackOnParmToNonPackOnArg = true;
break;
case TemplateDeductionResult::MiscellaneousDeductionFailure:
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 2f60c0beb22e73..de71774bd8e559 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -4017,11 +4017,11 @@ bool Sema::usesPartialOrExplicitSpecialization(
/// Get the instantiation pattern to use to instantiate the definition of a
/// given ClassTemplateSpecializationDecl (either the pattern of the primary
/// template or of a partial specialization).
-static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
+static ActionResult<CXXRecordDecl *>
+getPatternForClassTemplateSpecialization(
Sema &S, SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- TemplateSpecializationKind TSK,
- bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
+ TemplateSpecializationKind TSK) {
Sema::InstantiatingTemplate Inst(S, PointOfInstantiation, ClassTemplateSpec);
if (Inst.isInvalid())
return {/*Invalid=*/true};
@@ -4044,7 +4044,7 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
// specialization with the template argument lists of the partial
// specializations.
typedef PartialSpecMatchResult MatchResult;
- SmallVector<MatchResult, 4> Matched, ExtraMatched;
+ SmallVector<MatchResult, 4> Matched;
SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
Template->getPartialSpecializations(PartialSpecs);
TemplateSpecCandidateSet FailedCandidates(PointOfInstantiation);
@@ -4061,13 +4061,11 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
MakeDeductionFailureInfo(S.Context, Result, Info));
(void)Result;
} else {
- auto &List =
- Info.hasMatchedPackOnParmToNonPackOnArg() ? ExtraMatched : Matched;
- List.push_back(MatchResult{Partial, Info.takeCanonical()});
+ Matched.push_back(PartialSpecMatchResult());
+ Matched.back().Partial = Partial;
+ Matched.back().Args = Info.takeCanonical();
}
}
- if (Matched.empty() && PrimaryHasMatchedPackOnParmToNonPackOnArg)
- Matched = std::move(ExtraMatched);
// If we're dealing with a member template where the template parameters
// have been instantiated, this provides the original template parameters
@@ -4170,8 +4168,7 @@ static ActionResult<CXXRecordDecl *> getPatternForClassTemplateSpecialization(
bool Sema::InstantiateClassTemplateSpecialization(
SourceLocation PointOfInstantiation,
ClassTemplateSpecializationDecl *ClassTemplateSpec,
- TemplateSpecializationKind TSK, bool Complain,
- bool PrimaryHasMatchedPackOnParmToNonPackOnArg) {
+ TemplateSpecializationKind TSK, bool Complain) {
// Perform the actual instantiation on the canonical declaration.
ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
ClassTemplateSpec->getCanonicalDecl());
@@ -4179,9 +4176,8 @@ bool Sema::InstantiateClassTemplateSpecialization(
return true;
ActionResult<CXXRecordDecl *> Pattern =
- getPatternForClassTemplateSpecialization(
- *this, PointOfInstantiation, ClassTemplateSpec, TSK,
- PrimaryHasMatchedPackOnParmToNonPackOnArg);
+ getPatternForClassTemplateSpecialization(*this, PointOfInstantiation,
+ ClassTemplateSpec, TSK);
if (!Pattern.isUsable())
return Pattern.isInvalid();
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 56091e84cf4e95..b9e9e9f0c97f26 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -156,14 +156,16 @@ namespace ttp_defaults {
namespace ttp_only {
template <template <class... > class TT1> struct A { static constexpr int V = 0; };
template <template <class > class TT2> struct A<TT2> { static constexpr int V = 1; };
+ // new-note at -1 {{partial specialization matches}}
template <template <class, class> class TT3> struct A<TT3> { static constexpr int V = 2; };
+ // new-note at -1 {{partial specialization matches}}
template <class ... > struct B;
template <class > struct C;
template <class, class > struct D;
template <class, class, class> struct E;
- static_assert(A<B>::V == 0);
+ static_assert(A<B>::V == 0); // new-error {{ambiguous partial specializations}}
static_assert(A<C>::V == 1);
static_assert(A<D>::V == 2);
static_assert(A<E>::V == 0);
@@ -410,9 +412,11 @@ namespace partial {
template<template<class... T1s> class TT1> struct A {};
template<template<class T2> class TT2> struct A<TT2>;
+ // new-note at -1 {{template is declared here}}
template<class... T3s> struct B;
template struct A<B>;
+ // new-error at -1 {{explicit instantiation of undefined template}}
} // namespace t1
namespace t2 {
template<template<class... T1s> class TT1> struct A;
More information about the cfe-commits
mailing list