[clang] [clang] disallow narrowing when matching template template parameters (PR #124313)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Sat Jan 25 19:56:22 PST 2025
https://github.com/mizvekov updated https://github.com/llvm/llvm-project/pull/124313
>From 8210ac8a213a8409dc3b470fb295b70e8264934d Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sun, 12 Jan 2025 14:45:24 -0300
Subject: [PATCH] [clang] disallow narrowing when matching template template
parameters
This fixes the core issue described in P3579, following the design
intent of P0522 to not introduce any new cases where a template
template parameter match is allowed for a template which is not valid
for all possible uses.
With this patch, narrowing conversions is disallowed for TTP matching.
This reuses the existing machinery for diagnosing narrowing in
a converted constant expression.
Since P0522 is a DR and we apply it all the way back to C++98,
this brings that machinery to use in older standards, in this
very narrow scope of TTP matching.
This still doesn't solve the ambiguity when partial ordering NTTPs of
different integral types, this is blocked by a different bug which will
be fixed in a subsequent patch.
---
clang/docs/ReleaseNotes.rst | 3 +
.../clang/Basic/DiagnosticSemaKinds.td | 4 +-
clang/include/clang/Sema/Sema.h | 3 +
clang/lib/Sema/SemaLookup.cpp | 2 +-
clang/lib/Sema/SemaOverload.cpp | 23 +++--
clang/lib/Sema/SemaTemplate.cpp | 44 +++++----
clang/lib/Sema/SemaTemplateDeduction.cpp | 4 +-
clang/lib/Sema/SemaTemplateInstantiate.cpp | 7 +-
clang/test/CXX/drs/cwg0xx.cpp | 6 +-
clang/test/CXX/drs/cwg12xx.cpp | 2 +
clang/test/CXX/drs/cwg3xx.cpp | 16 +++-
clang/test/CXX/expr/expr.const/p3-0x.cpp | 8 +-
.../CXX/temp/temp.arg/temp.arg.nontype/p1.cpp | 15 +--
.../temp/temp.arg/temp.arg.template/p3-0x.cpp | 16 ++--
clang/test/Modules/cxx-templates.cpp | 5 +-
clang/test/SemaObjCXX/noescape.mm | 7 +-
clang/test/SemaTemplate/cwg2398.cpp | 95 +++++++++++++++++--
clang/test/SemaTemplate/default-arguments.cpp | 28 +++---
.../instantiate-template-template-parm.cpp | 4 +-
.../SemaTemplate/instantiation-default-2.cpp | 6 +-
clang/test/SemaTemplate/nested-template.cpp | 6 +-
.../SemaTemplate/temp_arg_nontype_cxx1z.cpp | 8 +-
.../SemaTemplate/temp_arg_nontype_cxx20.cpp | 4 +-
clang/test/SemaTemplate/temp_arg_template.cpp | 7 +-
.../SemaTemplate/temp_arg_template_p0522.cpp | 5 +-
25 files changed, 230 insertions(+), 98 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f110b8cf765075..b89d055304f4a6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -329,6 +329,9 @@ C++17 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- The implementation of the relaxed template template argument matching rules is
more complete and reliable, and should provide more accurate diagnostics.
+ This implements:
+ - `P3310R5: Solving issues introduced by relaxed template template parameter matching <https://wg21.link/p3310r5>`_.
+ - `P3579R0: Fix matching of non-type template parameters when matching template template parameters <https://wg21.link/p3579r0>`_.
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 774e5484cfa0e7..6be67a36b9fe7d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -82,11 +82,11 @@ def err_typecheck_converted_constant_expression_indirect : Error<
"conversion from %0 to %1 in converted constant expression would "
"bind reference to a temporary">;
def err_expr_not_cce : Error<
- "%select{case value|enumerator value|non-type template argument|"
+ "%select{case value|enumerator value|non-type template argument|non-type parameter of template template parameter|"
"array size|explicit specifier argument|noexcept specifier argument|"
"call to 'size()'|call to 'data()'}0 is not a constant expression">;
def ext_cce_narrowing : ExtWarn<
- "%select{case value|enumerator value|non-type template argument|"
+ "%select{case value|enumerator value|non-type template argument|non-type parameter of template template parameter|"
"array size|explicit specifier argument|noexcept specifier argument|"
"call to 'size()'|call to 'data()'}0 %select{cannot be narrowed from "
"type %2 to %3|evaluates to %2, which cannot be narrowed to type %3}1">,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4d6e02fe2956e0..1ea7c62cb36f05 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -9999,6 +9999,7 @@ class Sema final : public SemaBase {
CCEK_CaseValue, ///< Expression in a case label.
CCEK_Enumerator, ///< Enumerator value with fixed underlying type.
CCEK_TemplateArg, ///< Value of a non-type template parameter.
+ CCEK_InjectedTTP, ///< Injected parameter of a template template parameter.
CCEK_ArrayBound, ///< Array bound in array declarator or new-expression.
CCEK_ExplicitBool, ///< Condition in an explicit(bool) specifier.
CCEK_Noexcept, ///< Condition in a noexcept(bool) specifier.
@@ -11682,6 +11683,7 @@ class Sema final : public SemaBase {
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
CheckTemplateArgumentKind CTAK, bool PartialOrdering,
+ bool PartialOrderingTTP,
bool *MatchedPackOnParmToNonPackOnArg);
/// Check that the given template arguments can be provided to
@@ -11755,6 +11757,7 @@ class Sema final : public SemaBase {
QualType InstantiatedParamType, Expr *Arg,
TemplateArgument &SugaredConverted,
TemplateArgument &CanonicalConverted,
+ bool PartialOrderingTTP,
CheckTemplateArgumentKind CTAK);
/// Check a template argument against its corresponding
diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp
index 2ed8d3608d49ec..26f53532a1491f 100644
--- a/clang/lib/Sema/SemaLookup.cpp
+++ b/clang/lib/Sema/SemaLookup.cpp
@@ -3676,7 +3676,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (CheckTemplateArgument(
Params->getParam(0), Arg, FD, R.getNameLoc(), R.getNameLoc(),
0, SugaredChecked, CanonicalChecked, CTAK_Specified,
- /*PartialOrdering=*/false,
+ /*PartialOrdering=*/false, /*PartialOrderingTTP=*/false,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr) ||
Trap.hasErrorOccurred())
IsTemplate = false;
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index 6ae9c51c06b315..20eaf494e90bb8 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -6151,8 +6151,8 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
Sema::CCEKind CCE,
NamedDecl *Dest,
APValue &PreNarrowingValue) {
- assert(S.getLangOpts().CPlusPlus11 &&
- "converted constant expression outside C++11");
+ assert((S.getLangOpts().CPlusPlus11 || CCE == Sema::CCEK_InjectedTTP) &&
+ "converted constant expression outside C++11 or TTP matching");
if (checkPlaceholderForOverload(S, From))
return ExprError();
@@ -6221,8 +6221,10 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
// earlier, but that's not guaranteed to work when initializing an object of
// class type.
ExprResult Result;
+ bool IsTemplateArgument =
+ CCE == Sema::CCEK_TemplateArg || CCE == Sema::CCEK_InjectedTTP;
if (T->isRecordType()) {
- assert(CCE == Sema::CCEK_TemplateArg &&
+ assert(IsTemplateArgument &&
"unexpected class type converted constant expr");
Result = S.PerformCopyInitialization(
InitializedEntity::InitializeTemplateParameter(
@@ -6239,7 +6241,7 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
// A full-expression is [...] a constant-expression [...]
Result = S.ActOnFinishFullExpr(Result.get(), From->getExprLoc(),
/*DiscardedValue=*/false, /*IsConstexpr=*/true,
- CCE == Sema::CCEKind::CCEK_TemplateArg);
+ IsTemplateArgument);
if (Result.isInvalid())
return Result;
@@ -6248,9 +6250,6 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
QualType PreNarrowingType;
switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue,
PreNarrowingType)) {
- case NK_Dependent_Narrowing:
- // Implicit conversion to a narrower type, but the expression is
- // value-dependent so we can't tell whether it's actually narrowing.
case NK_Variable_Narrowing:
// Implicit conversion to a narrower type, and the value is not a constant
// expression. We'll diagnose this in a moment.
@@ -6271,6 +6270,14 @@ static ExprResult BuildConvertedConstantExpression(Sema &S, Expr *From,
<< PreNarrowingValue.getAsString(S.Context, PreNarrowingType) << T;
break;
+ case NK_Dependent_Narrowing:
+ // Implicit conversion to a narrower type, but the expression is
+ // value-dependent so we can't tell whether it's actually narrowing.
+ // For matching the parameters of a TTP, the conversion is ill-formed
+ // if it may narrow.
+ if (CCE != Sema::CCEK_InjectedTTP)
+ break;
+ [[fallthrough]];
case NK_Type_Narrowing:
// FIXME: It would be better to diagnose that the expression is not a
// constant expression.
@@ -6343,6 +6350,8 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value,
Expr::EvalResult Eval;
Eval.Diag = &Notes;
+ assert(CCE != Sema::CCEK_InjectedTTP && "unnexpected CCE Kind");
+
ConstantExprKind Kind;
if (CCE == Sema::CCEK_TemplateArg && T->isRecordType())
Kind = ConstantExprKind::ClassTemplateArgument;
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 38196c5c2bc125..210df2836eeb07 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -5205,7 +5205,7 @@ bool Sema::CheckTemplateArgument(
SmallVectorImpl<TemplateArgument> &SugaredConverted,
SmallVectorImpl<TemplateArgument> &CanonicalConverted,
CheckTemplateArgumentKind CTAK, bool PartialOrdering,
- bool *MatchedPackOnParmToNonPackOnArg) {
+ bool PartialOrderingTTP, bool *MatchedPackOnParmToNonPackOnArg) {
// Check template type parameters.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
return CheckTemplateTypeArgument(TTP, Arg, SugaredConverted,
@@ -5260,8 +5260,9 @@ bool Sema::CheckTemplateArgument(
Expr *E = Arg.getArgument().getAsExpr();
TemplateArgument SugaredResult, CanonicalResult;
unsigned CurSFINAEErrors = NumSFINAEErrors;
- ExprResult Res = CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult,
- CanonicalResult, CTAK);
+ ExprResult Res =
+ CheckTemplateArgument(NTTP, NTTPType, E, SugaredResult,
+ CanonicalResult, PartialOrderingTTP, CTAK);
if (Res.isInvalid())
return true;
// If the current template argument causes an error, give up now.
@@ -5326,7 +5327,8 @@ bool Sema::CheckTemplateArgument(
TemplateArgument SugaredResult, CanonicalResult;
E = CheckTemplateArgument(NTTP, NTTPType, E.get(), SugaredResult,
- CanonicalResult, CTAK_Specified);
+ CanonicalResult, /*PartialOrderingTTP=*/false,
+ CTAK_Specified);
if (E.isInvalid())
return true;
@@ -5585,11 +5587,11 @@ bool Sema::CheckTemplateArgumentList(
getExpandedPackSize(*Param))
Arg = Arg.getPackExpansionPattern();
TemplateArgumentLoc NewArgLoc(Arg, ArgLoc.getLocInfo());
- if (CheckTemplateArgument(*Param, NewArgLoc, Template, TemplateLoc,
- RAngleLoc, SugaredArgumentPack.size(),
- SugaredConverted, CanonicalConverted,
- CTAK_Specified, /*PartialOrdering=*/false,
- MatchedPackOnParmToNonPackOnArg))
+ if (CheckTemplateArgument(
+ *Param, NewArgLoc, Template, TemplateLoc, RAngleLoc,
+ SugaredArgumentPack.size(), SugaredConverted,
+ CanonicalConverted, CTAK_Specified, /*PartialOrdering=*/false,
+ /*PartialOrderingTTP=*/true, MatchedPackOnParmToNonPackOnArg))
return true;
Arg = NewArgLoc.getArgument();
CanonicalConverted.back().setIsDefaulted(
@@ -5601,11 +5603,11 @@ bool Sema::CheckTemplateArgumentList(
TemplateArgumentLoc(TemplateArgument::CreatePackCopy(Context, Args),
ArgLoc.getLocInfo());
} else {
- if (CheckTemplateArgument(*Param, ArgLoc, Template, TemplateLoc,
- RAngleLoc, SugaredArgumentPack.size(),
- SugaredConverted, CanonicalConverted,
- CTAK_Specified, /*PartialOrdering=*/false,
- MatchedPackOnParmToNonPackOnArg))
+ if (CheckTemplateArgument(
+ *Param, ArgLoc, Template, TemplateLoc, RAngleLoc,
+ SugaredArgumentPack.size(), SugaredConverted,
+ CanonicalConverted, CTAK_Specified, /*PartialOrdering=*/false,
+ PartialOrderingTTP, MatchedPackOnParmToNonPackOnArg))
return true;
CanonicalConverted.back().setIsDefaulted(
clang::isSubstitutedDefaultArgument(Context, ArgLoc.getArgument(),
@@ -5753,6 +5755,7 @@ bool Sema::CheckTemplateArgumentList(
if (CheckTemplateArgument(*Param, Arg, Template, TemplateLoc, RAngleLoc, 0,
SugaredConverted, CanonicalConverted,
CTAK_Specified, /*PartialOrdering=*/false,
+ /*PartialOrderingTTP=*/false,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr))
return true;
@@ -6740,6 +6743,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
QualType ParamType, Expr *Arg,
TemplateArgument &SugaredConverted,
TemplateArgument &CanonicalConverted,
+ bool PartialOrderingTTP,
CheckTemplateArgumentKind CTAK) {
SourceLocation StartLoc = Arg->getBeginLoc();
@@ -6930,17 +6934,21 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
IsConvertedConstantExpression = false;
}
- if (getLangOpts().CPlusPlus17) {
+ if (getLangOpts().CPlusPlus17 || PartialOrderingTTP) {
// C++17 [temp.arg.nontype]p1:
// A template-argument for a non-type template parameter shall be
// a converted constant expression of the type of the template-parameter.
APValue Value;
ExprResult ArgResult;
if (IsConvertedConstantExpression) {
- ArgResult = BuildConvertedConstantExpression(Arg, ParamType,
- CCEK_TemplateArg, Param);
- if (ArgResult.isInvalid())
+ ArgResult = BuildConvertedConstantExpression(
+ Arg, ParamType,
+ PartialOrderingTTP ? CCEK_InjectedTTP : CCEK_TemplateArg, Param);
+ assert(!ArgResult.isUnset());
+ if (ArgResult.isInvalid()) {
+ NoteTemplateParameterLocation(*Param);
return ExprError();
+ }
} else {
ArgResult = Arg;
}
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 7882d7a755d345..2b96692727a7c8 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2979,7 +2979,8 @@ static bool ConvertDeducedTemplateArgument(
? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
: Sema::CTAK_Deduced)
: Sema::CTAK_Specified,
- PartialOrdering, &MatchedPackOnParmToNonPackOnArg);
+ PartialOrdering, /*PartialOrderingTTP=*/false,
+ &MatchedPackOnParmToNonPackOnArg);
if (MatchedPackOnParmToNonPackOnArg)
Info.setMatchedPackOnParmToNonPackOnArg();
return Res;
@@ -3179,6 +3180,7 @@ static TemplateDeductionResult ConvertDeducedTemplateArguments(
Param, DefArg, TD, TD->getLocation(), TD->getSourceRange().getEnd(),
/*ArgumentPackIndex=*/0, SugaredBuilder, CanonicalBuilder,
Sema::CTAK_Specified, /*PartialOrdering=*/false,
+ /*PartialOrderingTTP=*/false,
/*MatchedPackOnParmToNonPackOnArg=*/nullptr)) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 3dc5696bd38216..862086a0c53408 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -2399,9 +2399,10 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr(
// The call to CheckTemplateArgument here produces the ImpCast.
TemplateArgument SugaredConverted, CanonicalConverted;
if (SemaRef
- .CheckTemplateArgument(E->getParameter(), SubstType,
- SubstReplacement.get(), SugaredConverted,
- CanonicalConverted, Sema::CTAK_Specified)
+ .CheckTemplateArgument(
+ E->getParameter(), SubstType, SubstReplacement.get(),
+ SugaredConverted, CanonicalConverted,
+ /*PartialOrderingTTP=*/false, Sema::CTAK_Specified)
.isInvalid())
return true;
return transformNonTypeTemplateParmRef(E->getAssociatedDecl(),
diff --git a/clang/test/CXX/drs/cwg0xx.cpp b/clang/test/CXX/drs/cwg0xx.cpp
index 15f469440c66f2..44a0eb520af221 100644
--- a/clang/test/CXX/drs/cwg0xx.cpp
+++ b/clang/test/CXX/drs/cwg0xx.cpp
@@ -521,12 +521,12 @@ namespace example1 {
namespace A {
int i;
}
-
+
namespace A1 {
using A::i;
using A::i;
}
-
+
void f()
{
using A::i;
@@ -1371,7 +1371,7 @@ namespace cwg92 { // cwg92: 4 c++17
// considered in this context. In C++17, we *do* perform an implicit
// conversion (which performs initialization), and the exception specification
// is part of the type of the parameter, so this is invalid.
- template<void() throw()> struct X {};
+ template<void() throw()> struct X {}; // since-cxx17-note {{template parameter is declared here}}
X<&f> xp;
// since-cxx17-error at -1 {{value of type 'void (*)() throw(int, float)' is not implicitly convertible to 'void (*)() throw()'}}
diff --git a/clang/test/CXX/drs/cwg12xx.cpp b/clang/test/CXX/drs/cwg12xx.cpp
index 344adb6d720231..e02a7e11b80b2a 100644
--- a/clang/test/CXX/drs/cwg12xx.cpp
+++ b/clang/test/CXX/drs/cwg12xx.cpp
@@ -155,6 +155,8 @@ namespace cwg1295 { // cwg1295: 4
// cxx98-14-error at -1 {{non-type template argument does not refer to any declaration}}
// cxx98-14-note@#cwg1295-Y {{template parameter is declared here}}
// since-cxx17-error@#cwg1295-y {{reference cannot bind to bit-field in converted constant expression}}
+ // since-cxx17-note@#cwg1295-Y {{template parameter is declared here}}
+
#if __cplusplus >= 201103L
const unsigned other = 0;
diff --git a/clang/test/CXX/drs/cwg3xx.cpp b/clang/test/CXX/drs/cwg3xx.cpp
index b5e07a66bb4eda..6c420ecd4c91db 100644
--- a/clang/test/CXX/drs/cwg3xx.cpp
+++ b/clang/test/CXX/drs/cwg3xx.cpp
@@ -444,7 +444,7 @@ namespace cwg329 { // cwg329: 3.5
// expected-note@#cwg329-b {{in instantiation of template class 'cwg329::A<char>' requested here}}
// expected-note@#cwg329-i {{previous definition is here}}
};
- A<int> a;
+ A<int> a;
A<char> b; // #cwg329-b
void test() {
@@ -688,9 +688,9 @@ namespace cwg341 { // cwg341: sup 1708
namespace B {
extern "C" int &cwg341_a = cwg341_a;
// expected-error at -1 {{redefinition of 'cwg341_a'}}
- // expected-note@#cwg341_a {{previous definition is here}}
+ // expected-note@#cwg341_a {{previous definition is here}}
}
- extern "C" void cwg341_b(); // #cwg341_b
+ extern "C" void cwg341_b(); // #cwg341_b
}
int cwg341_a;
// expected-error at -1 {{declaration of 'cwg341_a' in global scope conflicts with declaration with C language linkage}}
@@ -708,7 +708,7 @@ namespace cwg341 {
// expected-error at -1 {{declaration of 'cwg341_d' with C language linkage conflicts with declaration in global scope}}
// expected-note@#cwg341_d {{declared in global scope here}}
- namespace A { extern "C" int cwg341_e; } // #cwg341_e
+ namespace A { extern "C" int cwg341_e; } // #cwg341_e
namespace B { extern "C" void cwg341_e(); }
// expected-error at -1 {{redefinition of 'cwg341_e' as different kind of symbol}}
// expected-note@#cwg341_e {{previous definition is here}}
@@ -960,6 +960,7 @@ namespace cwg354 { // cwg354: 3.1 c++11
// cxx11-14-error@#cwg354-p0 {{null non-type template argument must be cast to template parameter type 'int *'}}
// cxx11-14-note@#cwg354-ptr {{template parameter is declared here}}
// since-cxx17-error@#cwg354-p0 {{conversion from 'int' to 'int *' is not allowed in a converted constant expression}}
+ // since-cxx17-note@#cwg354-ptr {{template parameter is declared here}}
ptr<(int*)0> p1;
// cxx98-error at -1 {{non-type template argument does not refer to any declaration}}
// cxx98-note@#cwg354-ptr {{template parameter is declared here}}
@@ -969,12 +970,14 @@ namespace cwg354 { // cwg354: 3.1 c++11
// cxx11-14-error@#cwg354-p2 {{null non-type template argument of type 'float *' does not match template parameter of type 'int *'}}
// cxx11-14-note@#cwg354-ptr {{template parameter is declared here}}
// since-cxx17-error@#cwg354-p2 {{value of type 'float *' is not implicitly convertible to 'int *'}}
+ // since-cxx17-note@#cwg354-ptr {{template parameter is declared here}}
ptr<(int S::*)0> p3; // #cwg354-p3
// cxx98-error@#cwg354-p3 {{non-type template argument does not refer to any declaration}}
// cxx98-note@#cwg354-ptr {{template parameter is declared here}}
// cxx11-14-error@#cwg354-p3 {{null non-type template argument of type 'int S::*' does not match template parameter of type 'int *'}}
// cxx11-14-note@#cwg354-ptr {{template parameter is declared here}}
// since-cxx17-error@#cwg354-p3 {{value of type 'int S::*' is not implicitly convertible to 'int *'}}
+ // since-cxx17-note@#cwg354-ptr {{template parameter is declared here}}
template<int*> int both(); // #cwg354-both-int-ptr
template<int> int both(); // #cwg354-both-int
@@ -991,6 +994,7 @@ namespace cwg354 { // cwg354: 3.1 c++11
// cxx11-14-error@#cwg354-m0 {{null non-type template argument must be cast to template parameter type 'int S::*'}}
// cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}}
// since-cxx17-error@#cwg354-m0 {{conversion from 'int' to 'int S::*' is not allowed in a converted constant expression}}
+ // since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}}
ptr_mem<(int S::*)0> m1;
// cxx98-error at -1 {{non-type template argument is not a pointer to member constant}}
ptr_mem<(float S::*)0> m2; // #cwg354-m2
@@ -999,12 +1003,14 @@ namespace cwg354 { // cwg354: 3.1 c++11
// cxx11-14-error@#cwg354-m2 {{null non-type template argument of type 'float S::*' does not match template parameter of type 'int S::*'}}
// cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}}
// since-cxx17-error@#cwg354-m2 {{value of type 'float S::*' is not implicitly convertible to 'int S::*'}}
+ // since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}}
ptr_mem<(int *)0> m3; // #cwg354-m3
// cxx98-error@#cwg354-m3 {{non-type template argument of type 'int *' cannot be converted to a value of type 'int S::*'}}
// cxx98-note@#cwg354-ptr_mem {{template parameter is declared here}}
// cxx11-14-error@#cwg354-m3 {{null non-type template argument of type 'int *' does not match template parameter of type 'int S::*'}}
// cxx11-14-note@#cwg354-ptr_mem {{template parameter is declared here}}
// since-cxx17-error@#cwg354-m3 {{value of type 'int *' is not implicitly convertible to 'int S::*'}}
+ // since-cxx17-note@#cwg354-ptr_mem {{template parameter is declared here}}
} // namespace cwg354
struct cwg355_S; // cwg355: 2.7
@@ -1116,7 +1122,7 @@ namespace cwg364 { // cwg364: 2.7
} // namespace cwg364
namespace cwg366 { // cwg366: 2.7
-#if "foo" // expected-error {{invalid token at start of a preprocessor expression}}
+#if "foo" // expected-error {{invalid token at start of a preprocessor expression}}
#endif
} // namespace cwg366
diff --git a/clang/test/CXX/expr/expr.const/p3-0x.cpp b/clang/test/CXX/expr/expr.const/p3-0x.cpp
index 5bd70c5250b598..3eedef3cf7712f 100644
--- a/clang/test/CXX/expr/expr.const/p3-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p3-0x.cpp
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s
-// RUN: %clang_cc1 -fsyntax-only -std=c++1z -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify=expected,cxx11 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify=expected,cxx17 %s
// A converted constant expression of type T is a core constant expression,
int nonconst = 8; // expected-note 3 {{here}}
@@ -66,7 +66,8 @@ enum class EEE : unsigned short {
e = 123456, // expected-error {{enumerator value evaluates to 123456, which cannot be narrowed to type 'unsigned short'}}
f = -3 // expected-error {{enumerator value evaluates to -3, which cannot be narrowed to type 'unsigned short'}}
};
-template<unsigned char> using A = int;
+template<unsigned char> using A = int; // cxx17-note 2{{template parameter is declared here}}
+
using Int = A<E6>;
using Int = A<EE::EE32>; // expected-error {{not implicitly convertible}}
using Int = A<(int)EE::EE32>;
@@ -78,6 +79,7 @@ using Int = A<-3>; // expected-error {{template argument evaluates to -3, which
// integral conversions as well as boolean conversions.
// FIXME: Per core issue 1407, this is not correct.
template<typename T, T v> struct Val { static constexpr T value = v; };
+// cxx17-note at -1 2{{template parameter is declared here}}
static_assert(Val<bool, E1>::value == 1, ""); // ok
static_assert(Val<bool, '\0'>::value == 0, ""); // ok
static_assert(Val<bool, U'\1'>::value == 1, ""); // ok
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
index 7fce6155169245..629000d88acc37 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.nontype/p1.cpp
@@ -8,7 +8,7 @@
// be one of:
// -- an integral constant expression; or
// -- the name of a non-type template-parameter ; or
-#ifndef CPP11ONLY
+#ifndef CPP11ONLY
namespace non_type_tmpl_param {
template <int N> struct X0 { X0(); };
@@ -31,15 +31,18 @@ namespace non_type_tmpl_param {
// omitted if the name refers to a function or array and shall be omitted
// if the corresopnding template-parameter is a reference; or
namespace addr_of_obj_or_func {
- template <int* p> struct X0 { }; // precxx17-note 5{{here}}
+ template <int* p> struct X0 { }; // expected-note 5{{here}}
#if __cplusplus >= 201103L
// precxx17-note at -2 2{{template parameter is declared here}}
#endif
- template <int (*fp)(int)> struct X1 { };
- template <int &p> struct X2 { }; // precxx17-note 4{{here}}
- template <const int &p> struct X2k { }; // precxx17-note {{here}}
- template <int (&fp)(int)> struct X3 { }; // precxx17-note 4{{here}}
+ template <int (*fp)(int)> struct X1 { }; // cxx17-note {{here}}
+#if __cplusplus <= 199711L
+ // precxx17-note at -2 {{here}}
+#endif
+ template <int &p> struct X2 { }; // expected-note 4{{here}}
+ template <const int &p> struct X2k { }; // expected-note {{here}}
+ template <int (&fp)(int)> struct X3 { }; // expected-note 4{{here}}
int i = 42;
#if __cplusplus >= 201103L
diff --git a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
index 54fcfccad6f520..3caed045c6688b 100644
--- a/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
+++ b/clang/test/CXX/temp/temp.arg/temp.arg.template/p3-0x.cpp
@@ -18,8 +18,9 @@ eval<D<int, 17>> eD; // expected-error{{implicit instantiation of undefined temp
eval<E<int, float>> eE; // expected-error{{implicit instantiation of undefined template 'eval<E<int, float>>}}
template<
- template <int ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'void *')}}
- class TT // expected-note {{previous template template parameter is here}}
+ template <int ...N> // expected-error {{cannot be narrowed from type 'int' to 'short'}}
+ // expected-error at -1 {{conversion from 'int' to 'void *' is not allowed in a converted constant expression}}
+ class TT // expected-note 2{{previous template template parameter is here}}
> struct X0 { };
template<int I, int J, int ...Rest> struct X0a;
@@ -31,12 +32,13 @@ template<int I, void *J> struct X0e; // expected-note{{template parameter is dec
X0<X0a> inst_x0a;
X0<X0b> inst_x0b;
X0<X0c> inst_x0c;
-X0<X0d> inst_x0d;
+X0<X0d> inst_x0d; // expected-note {{has different template parameters}}
X0<X0e> inst_x0e; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}}
template<typename T,
- template <T ...N> // expected-error{{deduced non-type template argument does not have the same type as the corresponding template parameter ('short' vs 'void *')}}
- class TT // expected-note {{previous template template parameter is here}}
+ template <T ...N> // expected-error {{conversion from 'short' to 'void *' is not allowed in a converted constant expression}}
+ // expected-error at -1 {{cannot be narrowed from type 'int' to 'short'}}
+ class TT // expected-note 2{{previous template template parameter is here}}
> struct X1 { };
template<int I, int J, int ...Rest> struct X1a;
@@ -49,8 +51,8 @@ X1<int, X1a> inst_x1a;
X1<long, X1b> inst_x1b;
X1<short, X1c> inst_x1c;
X1<short, X1d> inst_sx1d;
-X1<int, X1d> inst_ix1d;
-X1<short, X1e> inst_x1e; // expected-note{{template template argument has different template parameters than its corresponding template template parameter}}
+X1<int, X1d> inst_ix1d; // expected-note {{has different template parameters}}
+X1<short, X1e> inst_x1e; // expected-note {{has different template parameters}}
template <int> class X2; // expected-note{{template is declared here}} \
// expected-note{{template is declared here}}
diff --git a/clang/test/Modules/cxx-templates.cpp b/clang/test/Modules/cxx-templates.cpp
index b197f319e0d153..f587af4beb7ceb 100644
--- a/clang/test/Modules/cxx-templates.cpp
+++ b/clang/test/Modules/cxx-templates.cpp
@@ -40,7 +40,10 @@ void g() {
template_param_kinds_1<0>(); // ok, from cxx-templates-a.h
template_param_kinds_1<int>(); // ok, from cxx-templates-b.h
- template_param_kinds_2<Tmpl_T_C>(); // ok, from cxx-templates-b.h
+
+ template_param_kinds_2<Tmpl_T_C>(); // expected-error {{no matching function for call}}
+ // expected-note at Inputs/cxx-templates-a.h:11 {{candidate}}
+ // expected-note at Inputs/cxx-templates-b.h:11 {{candidate}}
template_param_kinds_2<Tmpl_T_I_I>(); // expected-error {{ambiguous}}
// expected-note at Inputs/cxx-templates-a.h:11 {{candidate}}
diff --git a/clang/test/SemaObjCXX/noescape.mm b/clang/test/SemaObjCXX/noescape.mm
index 999a91b87300b7..4484e3b955ac03 100644
--- a/clang/test/SemaObjCXX/noescape.mm
+++ b/clang/test/SemaObjCXX/noescape.mm
@@ -77,12 +77,11 @@ -(void) m0:(int*) p {}
void (*fnptr0)(int *);
void (*fnptr1)(__attribute__((noescape)) int *);
template<void (*fn)(int*)> struct S4 {};
-template<void (*fn)(int* __attribute__((noescape)))> struct S5 {};
-
#if __cplusplus < 201406
- // expected-note at -4 {{template parameter is declared here}}
- // expected-note at -4 {{template parameter is declared here}}
+// expected-note at -2 {{template parameter is declared here}}
#endif
+template<void (*fn)(int* __attribute__((noescape)))> struct S5 {};
+// expected-note at -1 {{template parameter is declared here}}
void test0() {
fnptr0 = &func0;
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index 21a1b89ce79b4e..1d35b574176a7e 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -362,15 +362,17 @@ namespace classes {
namespace packs {
namespace t1 {
- // FIXME: This should be rejected
template<template<int, int...> class> struct A {};
- // old-note at -1 {{previous non-type template parameter with type 'int' is here}}
+ // new-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
+ // new-note at -2 {{previous template template parameter is here}}
+ // old-note at -3 {{previous non-type template parameter with type 'int' is here}}
template<char> struct B;
// old-note at -1 {{template non-type parameter has a different type 'char' in template argument}}
template struct A<B>;
- // old-error at -1 {{has different template parameters}}
+ // new-note at -1 {{has different template parameters}}
+ // old-error at -2 {{has different template parameters}}
} // namespace t1
namespace t2 {
template<template<char, int...> class> struct A {};
@@ -383,15 +385,17 @@ namespace packs {
// old-error at -1 {{has different template parameters}}
} // namespace t2
namespace t3 {
- // FIXME: This should be rejected
template<template<int...> class> struct A {};
- // old-note at -1 {{previous non-type template parameter with type 'int' is here}}
+ // new-error at -1 {{non-type parameter of template template parameter cannot be narrowed from type 'int' to 'char'}}
+ // new-note at -2 {{previous template template parameter is here}}
+ // old-note at -3 {{previous non-type template parameter with type 'int' is here}}
template<char> struct B;
// old-note at -1 {{template non-type parameter has a different type 'char' in template argument}}
template struct A<B>;
- // old-error at -1 {{has different template parameters}}
+ // new-note at -1 {{has different template parameters}}
+ // old-error at -2 {{has different template parameters}}
} // namespace t3
namespace t4 {
template<template<char...> class> struct A {};
@@ -427,6 +431,14 @@ namespace fun_tmpl_call {
template <class...> struct A {};
void test() { f(A<int>()); }
} // namespace order_func_pack
+ namespace match_enum {
+ enum A {};
+ template<template<A> class TT1> void f(TT1<{}>) {}
+ // old-note at -1 {{invalid explicitly-specified argument}}
+ template<int> struct B {};
+ template void f<B>(B<{}>);
+ // old-error at -1 {{does not refer to a function template}}
+ } // namespace match_enum
namespace match_method {
struct A {
template <template <class> class TT> void f(TT<int>) {};
@@ -435,7 +447,7 @@ namespace fun_tmpl_call {
template <class...> struct B {};
void test() { A().f(B<int>()); }
// old-error at -1 {{no matching member function for call to 'f'}}
- } // namespace t2
+ } // namespace match_method
namespace order_method_nonpack {
struct A {
template <template <class> class TT> void f(TT<int>) {}
@@ -648,3 +660,72 @@ namespace nttp_auto {
// new-note at -1 {{different template parameters}}
} // namespace t3
} // namespace nttp_auto
+
+namespace nttp_partial_order {
+ namespace t1 {
+ // FIXME: This should pick the second overload.
+ template<template<short> class TT1> void f(TT1<0>);
+ // new-note at -1 {{here}}
+ template<template<int> class TT2> void f(TT2<0>) {}
+ // new-note at -1 {{here}}
+ template<int> struct B {};
+ template void f<B>(B<0>);
+ // new-error at -1 {{ambiguous}}
+ } // namespace t1
+ namespace t2 {
+ // FIXME: This should pick the second overload.
+ struct A {} a;
+ template<template<A&> class TT1> void f(TT1<a>);
+ // new-note at -1 {{here}}
+ template<template<const A&> class TT2> void f(TT2<a>) {}
+ // new-note at -1 {{here}}
+ template<const A&> struct B {};
+ template void f<B>(B<a>);
+ // new-error at -1 {{ambiguous}}
+ } // namespace t2
+ namespace t3 {
+ // FIXME: This should pick the second overload.
+ enum A {};
+ template<template<A> class TT1> void f(TT1<{}>);
+ // new-note at -1 {{here}}
+ template<template<int> class TT2> void f(TT2<{}>) {}
+ // new-note at -1 {{here}}
+ template<int> struct B {};
+ template void f<B>(B<{}>);
+ // new-error at -1 {{ambiguous}}
+ } // namespace t3
+ namespace t4 {
+ // FIXME: This should pick the second overload.
+ struct A {} a;
+ template<template<A*> class TT1> void f(TT1<&a>);
+ // new-note at -1 {{here}}
+ template<template<const A*> class TT2> void f(TT2<&a>) {}
+ // new-note at -1 {{here}}
+ template<const A*> struct B {};
+ template void f<B>(B<&a>);
+ // new-error at -1 {{ambiguous}}
+ } // namespace t4
+ namespace t5 {
+ // FIXME: This should pick the second overload.
+ struct A { int m; };
+ template<template<int A::*> class TT1> void f(TT1<&A::m>);
+ // new-note at -1 {{here}}
+ template<template<const int A::*> class TT2> void f(TT2<&A::m>) {}
+ // new-note at -1 {{here}}
+ template<const int A::*> struct B {};
+ template void f<B>(B<&A::m>);
+ // new-error at -1 {{ambiguous}}
+ } // namespace t5
+ namespace t6 {
+ // FIXME: This should pick the second overload.
+ struct A {};
+ using nullptr_t = decltype(nullptr);
+ template<template<nullptr_t> class TT2> void f(TT2<nullptr>);
+ // new-note at -1 {{here}}
+ template<template<A*> class TT1> void f(TT1<nullptr>) {}
+ // new-note at -1 {{here}}
+ template<A*> struct B {};
+ template void f<B>(B<nullptr>);
+ // new-error at -1 {{ambiguous}}
+ } // namespace t6
+} // namespace nttp_partial_order
diff --git a/clang/test/SemaTemplate/default-arguments.cpp b/clang/test/SemaTemplate/default-arguments.cpp
index 3b1fbda414c12b..5ea34c0254ec1c 100644
--- a/clang/test/SemaTemplate/default-arguments.cpp
+++ b/clang/test/SemaTemplate/default-arguments.cpp
@@ -52,20 +52,20 @@ struct X2 {
template<typename U = typename X1<T>::type> // expected-error{{no type named 'type' in 'X1<int>'}} \
// expected-error{{no type named 'type' in 'X1<char>'}}
struct Inner1 { }; // expected-note{{template is declared here}}
-
+
template<T Value = X1<T>::value> // expected-error{{no member named 'value' in 'X1<int>'}} \
// expected-error{{no member named 'value' in 'X1<char>'}}
struct NonType1 { }; // expected-note{{template is declared here}}
-
+
template<T Value>
struct Inner2 { };
-
+
template<typename U>
struct Inner3 {
template<typename X = T, typename V = U>
struct VeryInner { };
-
- template<T Value1 = sizeof(T), T Value2 = sizeof(U),
+
+ template<T Value1 = sizeof(T), T Value2 = sizeof(U),
T Value3 = Value1 + Value2>
struct NonType2 { };
};
@@ -89,11 +89,11 @@ struct is_same { static const bool value = false; };
template<typename T>
struct is_same<T, T> { static const bool value = true; };
-int array1[is_same<__typeof__(vi),
+int array1[is_same<__typeof__(vi),
X2<int>::Inner3<float>::VeryInner<int, float> >::value? 1 : -1];
int array2[is_same<__typeof(x2_deep_nontype),
- X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int),
+ X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int),
sizeof(char)+sizeof(int)> >::value? 1 : -1];
// Template template parameter defaults
@@ -109,18 +109,20 @@ struct add_pointer {
template<typename T, template<typename> class X = T::template apply>
struct X4;
-int array4[is_same<X4<add_pointer>,
+int array4[is_same<X4<add_pointer>,
X4<add_pointer, add_pointer::apply> >::value? 1 : -1];
template<int> struct X5 {};
-template<long> struct X5b {};
-template<typename T,
- template<T> class B = X5>
+template<long long> struct X5b {};
+template<typename T,
+ template<T> class B = X5> // expected-error {{cannot be narrowed from type 'long long' to 'int'}}
+ // expected-note at -1 {{has different template parameters}}
+ // expected-note at -2 {{previous template template parameter is here}}
struct X6 {};
X6<int> x6a;
-X6<long> x6b;
-X6<long, X5b> x6c;
+X6<long long> x6b; // expected-note {{while checking a default template argument used here}}
+X6<long long, X5b> x6c;
template<template<class> class X = B<int> > struct X7; // expected-error{{must be a class template}}
diff --git a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
index 39aeeb1c1a6a32..dce30aa2af4ee3 100644
--- a/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
+++ b/clang/test/SemaTemplate/instantiate-template-template-parm.cpp
@@ -24,11 +24,13 @@ template<int> struct B;
template<typename T,
template<T Value> class X> // expected-error{{cannot have type 'float'}}
+ // expected-error at -1 {{cannot be narrowed from type 'long long' to 'int'}}
+ // expected-note at -2 {{previous template template parameter is here}}
struct X0 { };
X0<int, B> x0b1;
X0<float, B> x0b2; // expected-note{{while substituting}}
-X0<long, B> x0b3;
+X0<long long, B> x0b3; // expected-note {{has different template parameters}}
template<template<int V> class TT>
struct X1 { };
diff --git a/clang/test/SemaTemplate/instantiation-default-2.cpp b/clang/test/SemaTemplate/instantiation-default-2.cpp
index 99c25000bcb0b0..ffa77cf1ee5678 100644
--- a/clang/test/SemaTemplate/instantiation-default-2.cpp
+++ b/clang/test/SemaTemplate/instantiation-default-2.cpp
@@ -2,8 +2,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx17,precxx20 -std=c++17 %s
// RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx20 %std_cxx20- %s
-template<typename T, T Value> struct Constant; // precxx17-note{{template parameter is declared here}} \
-// FIXME: bad location precxx20-error{{a non-type template parameter cannot have type 'float'}}
+template<typename T, T Value> struct Constant;
+// FIXME: bad location precxx20-error at -1 {{a non-type template parameter cannot have type 'float'}}
+// expected-note at -2 {{template parameter is declared here}}
+// cxx20-note at -3 {{template parameter is declared here}}
Constant<int, 5> *c1;
diff --git a/clang/test/SemaTemplate/nested-template.cpp b/clang/test/SemaTemplate/nested-template.cpp
index a54992a3971878..4d7f2d9c5c9469 100644
--- a/clang/test/SemaTemplate/nested-template.cpp
+++ b/clang/test/SemaTemplate/nested-template.cpp
@@ -112,7 +112,9 @@ template struct X1<int>::B<bool>;
// Template template parameters
template<typename T>
struct X2 {
- template<template<class U, T Value> class> // expected-error{{cannot have type 'float'}}
+ template<template<class U, T Value> class> // expected-error {{cannot have type 'float'}}
+ // expected-error at -1 {{cannot be narrowed from type 'long long' to 'int'}}
+ // expected-note at -2 {{previous template template parameter is here}}
struct Inner { };
};
@@ -121,7 +123,7 @@ template<typename T, int Value>
X2<int>::Inner<X2_arg> x2i1;
X2<float> x2a; // expected-note{{instantiation}}
-X2<long>::Inner<X2_arg> x2i3;
+X2<long long>::Inner<X2_arg> x2i3; // expected-note {{has different template parameters}}
namespace PR10896 {
template<typename TN>
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
index 8d9356bb3201cd..c35743b87adbca 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx1z.cpp
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
-template<typename T, T val> struct A {};
+template<typename T, T val> struct A {}; // expected-note 3{{template parameter is declared here}}
template<typename T, typename U> constexpr bool is_same = false;
template<typename T> constexpr bool is_same<T, T> = true;
@@ -122,13 +122,13 @@ namespace DeduceDifferentType {
int a_imp = a(A<3>()); // expected-error {{no matching function}}
int a_exp = a<3>(A<3>());
- template<decltype(nullptr)> struct B {};
+ template<decltype(nullptr)> struct B {}; // expected-note {{template parameter is declared here}}
template<int *P> int b(B<P>); // expected-error {{value of type 'int *' is not implicitly convertible to 'decltype(nullptr)'}}
int b_imp = b(B<nullptr>()); // expected-error {{no matching function}}
int b_exp = b<nullptr>(B<nullptr>()); // expected-error {{no matching function}}
struct X { constexpr operator int() { return 0; } } x;
- template<X &> struct C {};
+ template<X &> struct C {}; // expected-note {{template parameter is declared here}}
template<int N> int c(C<N>); // expected-error {{value of type 'int' is not implicitly convertible to 'X &'}}
int c_imp = c(C<x>()); // expected-error {{no matching function}}
int c_exp = c<x>(C<x>()); // expected-error {{no matching function}}
@@ -448,7 +448,7 @@ namespace PR42108 {
struct R {};
struct S { constexpr S() {} constexpr S(R) {} };
struct T { constexpr operator S() { return {}; } };
- template <const S &> struct A {};
+ template <const S &> struct A {}; // expected-note {{template parameter is declared here}}
void f() {
A<R{}>(); // expected-error {{would bind reference to a temporary}}
A<S{}>(); // expected-error {{reference to temporary object}}
diff --git a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
index ad73daa8e214c3..56ceb7af4ccd93 100644
--- a/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
+++ b/clang/test/SemaTemplate/temp_arg_nontype_cxx20.cpp
@@ -101,7 +101,7 @@ namespace ConvertedConstant {
struct {
int i : 2;
} b;
- template <const int&> struct Y {};
+ template <const int&> struct Y {}; // expected-note {{template parameter is declared here}}
void f(Y<b.i>) {} // expected-error {{reference cannot bind to bit-field in converted constant expression}}
}
@@ -238,7 +238,7 @@ namespace UnnamedBitfield {
}
namespace Temporary {
- template<const int &> struct A {};
+ template<const int &> struct A {}; // expected-note {{template parameter is declared here}}
A<0> a0; // expected-error {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}}
A<(const int&)1> a1; // expected-error {{reference to temporary object is not allowed in a template argument}}
diff --git a/clang/test/SemaTemplate/temp_arg_template.cpp b/clang/test/SemaTemplate/temp_arg_template.cpp
index 9908af5e78669d..aa53dba652050e 100644
--- a/clang/test/SemaTemplate/temp_arg_template.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template.cpp
@@ -7,14 +7,13 @@ template<template<typename T> class X> struct A; // #A
template<template<typename T, int I> class X> struct B; // expected-note{{previous template template parameter is here}}
template<template<int I> class X> struct C;
-// precxx17-error at -1 {{deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'const int &')}}
-// cxx17-error at -2 {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}}
-// expected-note at -3 {{previous template template parameter is here}}
+// expected-error at -1 {{conversion from 'int' to 'const int &' in converted constant expression would bind reference to a temporary}}
+// expected-note at -2 {{previous template template parameter is here}}
template<class> struct X; // expected-note {{template is declared here}}
template<int N> struct Y; // expected-note {{template parameter is declared here}}
template<long N> struct Ylong;
-template<const int &N> struct Yref; // precxx17-note {{template parameter is declared here}}
+template<const int &N> struct Yref; // expected-note {{template parameter is declared here}}
namespace N {
template<class> struct Z;
diff --git a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
index dcfc7b5b272880..2e5a36ae6ed082 100644
--- a/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
+++ b/clang/test/SemaTemplate/temp_arg_template_p0522.cpp
@@ -66,8 +66,9 @@ namespace DependentType {
using ok = Pt<tT0<int, i>, tT0<int, iDi>>;
using err1 = tT0<int, ii>; // expected-error {{too few template arguments for class template 'ii'}}
// expected-note at -1 {{different template parameters}}
- using err2 = tT0<short, i>; // FIXME: should this be OK?
- using err2a = tT0<long long, i>; // FIXME: should this be OK (if long long is larger than int)?
+ using err2 = tT0<short, i>;
+ using err2a = tT0<long long, i>; // expected-error@#tT0 {{cannot be narrowed from type 'long long' to 'int'}}
+ // expected-note at -1 {{different template parameters}}
using err2b = tT0<void*, i>; // expected-error@#tT0 {{value of type 'void *' is not implicitly convertible to 'int'}}
// expected-note at -1 {{different template parameters}}
using err3 = tT0<short, t0>; // expected-error@#tT0 {{template argument for template type parameter must be a type}}
More information about the cfe-commits
mailing list