[clang] [Clang] Implement CWG2369 "Ordering between constraints and substitution" (PR #102857)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 12 00:35:29 PDT 2024
https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/102857
Some things are not completed yet:
- [ ] CWG2369 for lambdas. We currently don't perform the concept checking before the substitution into lambdas because that requires us to put/instantiate captures to the scope, which is much more arduous than we should've done for ordinary functions. So constraints checking for lambdas are left as-is for now.
- [ ] Code cleanups, refactoring.
- [ ] Instantiate "used" parameters that a type constraint references to. Currently this patch instantiates all function parameters before checking the constraint.
Closes https://github.com/llvm/llvm-project/issues/54440
>From de90a38cd1e8c1ea9316a05e0f68a56fd5a7240b Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Sun, 11 Aug 2024 16:51:34 +0800
Subject: [PATCH 1/2] CWG 2369
---
clang/include/clang/Sema/Sema.h | 3 +-
clang/lib/Sema/SemaConcept.cpp | 2 +-
clang/lib/Sema/SemaTemplateDeduction.cpp | 94 ++++++++++++++++---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 5 +-
.../lib/Sema/SemaTemplateInstantiateDecl.cpp | 48 +++++++---
5 files changed, 122 insertions(+), 30 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 2ec6367eccea01..bd7b4c2d9b97ec 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13058,7 +13058,8 @@ class Sema final : public SemaBase {
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false,
- bool SkipForSpecialization = false);
+ bool SkipForSpecialization = false,
+ MultiLevelTemplateArgumentList *Merged = nullptr);
/// RAII object to handle the state changes required to synthesize
/// a function body.
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index d4c9d044985e34..45318109d47963 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -842,7 +842,7 @@ bool Sema::CheckFunctionConstraints(const FunctionDecl *FD,
bool ForOverloadResolution) {
// Don't check constraints if the function is dependent. Also don't check if
// this is a function template specialization, as the call to
- // CheckinstantiatedFunctionTemplateConstraints after this will check it
+ // CheckInstantiatedFunctionTemplateConstraints after this will check it
// better.
if (FD->isDependentContext() ||
FD->getTemplatedKind() ==
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 978f1a9dc1a933..1880104625e4cb 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3834,18 +3834,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
Result != TemplateDeductionResult::Success)
return Result;
- // C++ [temp.deduct.call]p10: [DR1391]
- // If deduction succeeds for all parameters that contain
- // template-parameters that participate in template argument deduction,
- // and all template arguments are explicitly specified, deduced, or
- // obtained from default template arguments, remaining parameters are then
- // compared with the corresponding arguments. For each remaining parameter
- // P with a type that was non-dependent before substitution of any
- // explicitly-specified template arguments, if the corresponding argument
- // A cannot be implicitly converted to P, deduction fails.
- if (CheckNonDependent())
- return TemplateDeductionResult::NonDependentConversionFailure;
-
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *SugaredDeducedArgumentList =
TemplateArgumentList::CreateCopy(Context, SugaredBuilder);
@@ -3875,6 +3863,76 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
FD = const_cast<FunctionDecl *>(FDFriend);
Owner = FD->getLexicalDeclContext();
}
+#if 1
+ // FIXME: We have to partially instantiate lambda's captures for constraint
+ // evaluation.
+ if (!isLambdaCallOperator(FD) && !isLambdaConversionOperator(FD) &&
+ (!PartialOverloading ||
+ (CanonicalBuilder.size() ==
+ FunctionTemplate->getTemplateParameters()->size()))) {
+ FunctionTemplateDecl *Template = FunctionTemplate->getCanonicalDecl();
+ FunctionDecl *FD = Template->getTemplatedDecl();
+ SmallVector<const Expr *, 3> TemplateAC;
+ Template->getAssociatedConstraints(TemplateAC);
+ if (!TemplateAC.empty()) {
+
+ // Enter the scope of this instantiation. We don't use
+ // PushDeclContext because we don't have a scope.
+ LocalInstantiationScope Scope(*this);
+
+ // Collect the list of template arguments relative to the 'primary'
+ // template. We need the entire list, since the constraint is completely
+ // uninstantiated at this point.
+
+ MultiLevelTemplateArgumentList MLTAL(FD, SugaredBuilder, /*Final=*/false);
+ getTemplateInstantiationArgs(nullptr, FD->getLexicalDeclContext(),
+ /*Final=*/false,
+ /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true,
+ /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/true,
+ /*SkipForSpecialization=*/false,
+ /*Merged=*/&MLTAL);
+
+ // if (SetupConstraintScope(FD, SugaredBuilder, MLTAL, Scope))
+ // return TemplateDeductionResult::MiscellaneousDeductionFailure;
+
+ MultiLevelTemplateArgumentList JustTemplArgs(
+ Template, CanonicalDeducedArgumentList->asArray(),
+ /*Final=*/false);
+ if (addInstantiatedParametersToScope(nullptr, FD, Scope, JustTemplArgs))
+ return TemplateDeductionResult::MiscellaneousDeductionFailure;
+
+ if (FunctionTemplateDecl *FromMemTempl =
+ Template->getInstantiatedFromMemberTemplate()) {
+ while (FromMemTempl->getInstantiatedFromMemberTemplate())
+ FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate();
+ if (addInstantiatedParametersToScope(
+ nullptr, FromMemTempl->getTemplatedDecl(), Scope, MLTAL))
+ return TemplateDeductionResult::MiscellaneousDeductionFailure;
+ }
+
+ Qualifiers ThisQuals;
+ CXXRecordDecl *Record = nullptr;
+ if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+ ThisQuals = Method->getMethodQualifiers();
+ Record = Method->getParent();
+ }
+ CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
+ llvm::SmallVector<Expr *, 1> Converted;
+ if (CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
+ Template->getSourceRange(),
+ Info.AssociatedConstraintsSatisfaction))
+ return TemplateDeductionResult::MiscellaneousDeductionFailure;
+ if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
+ Info.reset(TemplateArgumentList::CreateCopy(Context, SugaredBuilder),
+ Info.takeCanonical());
+ return TemplateDeductionResult::ConstraintsNotSatisfied;
+ }
+ }
+ }
+#endif
+
MultiLevelTemplateArgumentList SubstArgs(
FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
/*Final=*/false);
@@ -3924,6 +3982,18 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
}
}
+ // C++ [temp.deduct.call]p10: [DR1391]
+ // If deduction succeeds for all parameters that contain
+ // template-parameters that participate in template argument deduction,
+ // and all template arguments are explicitly specified, deduced, or
+ // obtained from default template arguments, remaining parameters are then
+ // compared with the corresponding arguments. For each remaining parameter
+ // P with a type that was non-dependent before substitution of any
+ // explicitly-specified template arguments, if the corresponding argument
+ // A cannot be implicitly converted to P, deduction fails.
+ if (CheckNonDependent())
+ return TemplateDeductionResult::NonDependentConversionFailure;
+
// We skipped the instantiation of the explicit-specifier during the
// substitution of `FD` before. So, we try to instantiate it back if
// `Specialization` is either a constructor or a conversion function.
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index de470739ab78e7..663bc6a57b0d91 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -467,10 +467,11 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
- bool SkipForSpecialization) {
+ bool SkipForSpecialization, MultiLevelTemplateArgumentList *Merged) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
- MultiLevelTemplateArgumentList Result;
+ MultiLevelTemplateArgumentList Ret;
+ MultiLevelTemplateArgumentList &Result = Merged ? *Merged : Ret;
using namespace TemplateInstArgsHelpers;
const Decl *CurDecl = ND;
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index f93cd113988ae4..5a7cb294a1c86d 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4577,17 +4577,17 @@ void Sema::addInstantiatedLocalVarsToScope(FunctionDecl *Function,
}
}
-bool Sema::addInstantiatedParametersToScope(
- FunctionDecl *Function, const FunctionDecl *PatternDecl,
- LocalInstantiationScope &Scope,
+static bool addInstantiatedParametersToScope(
+ Sema &SemaRef, MutableArrayRef<ParmVarDecl *> InstantiatedParamDecls,
+ const FunctionDecl *PatternDecl, LocalInstantiationScope &Scope,
const MultiLevelTemplateArgumentList &TemplateArgs) {
unsigned FParamIdx = 0;
for (unsigned I = 0, N = PatternDecl->getNumParams(); I != N; ++I) {
const ParmVarDecl *PatternParam = PatternDecl->getParamDecl(I);
if (!PatternParam->isParameterPack()) {
// Simple case: not a parameter pack.
- assert(FParamIdx < Function->getNumParams());
- ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+ assert(FParamIdx < InstantiatedParamDecls.size());
+ ParmVarDecl *FunctionParam = InstantiatedParamDecls[FParamIdx];
FunctionParam->setDeclName(PatternParam->getDeclName());
// If the parameter's type is not dependent, update it to match the type
// in the pattern. They can differ in top-level cv-qualifiers, and we want
@@ -4596,9 +4596,9 @@ bool Sema::addInstantiatedParametersToScope(
// it's instantiation-dependent.
// FIXME: Updating the type to work around this is at best fragile.
if (!PatternDecl->getType()->isDependentType()) {
- QualType T = SubstType(PatternParam->getType(), TemplateArgs,
- FunctionParam->getLocation(),
- FunctionParam->getDeclName());
+ QualType T = SemaRef.SubstType(PatternParam->getType(), TemplateArgs,
+ FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
if (T.isNull())
return true;
FunctionParam->setType(T);
@@ -4612,18 +4612,19 @@ bool Sema::addInstantiatedParametersToScope(
// Expand the parameter pack.
Scope.MakeInstantiatedLocalArgPack(PatternParam);
std::optional<unsigned> NumArgumentsInExpansion =
- getNumArgumentsInExpansion(PatternParam->getType(), TemplateArgs);
+ SemaRef.getNumArgumentsInExpansion(PatternParam->getType(),
+ TemplateArgs);
if (NumArgumentsInExpansion) {
QualType PatternType =
PatternParam->getType()->castAs<PackExpansionType>()->getPattern();
for (unsigned Arg = 0; Arg < *NumArgumentsInExpansion; ++Arg) {
- ParmVarDecl *FunctionParam = Function->getParamDecl(FParamIdx);
+ ParmVarDecl *FunctionParam = InstantiatedParamDecls[FParamIdx];
FunctionParam->setDeclName(PatternParam->getDeclName());
if (!PatternDecl->getType()->isDependentType()) {
- Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, Arg);
- QualType T =
- SubstType(PatternType, TemplateArgs, FunctionParam->getLocation(),
- FunctionParam->getDeclName());
+ Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, Arg);
+ QualType T = SemaRef.SubstType(PatternType, TemplateArgs,
+ FunctionParam->getLocation(),
+ FunctionParam->getDeclName());
if (T.isNull())
return true;
FunctionParam->setType(T);
@@ -4638,6 +4639,25 @@ bool Sema::addInstantiatedParametersToScope(
return false;
}
+bool Sema::addInstantiatedParametersToScope(
+ FunctionDecl *Function, const FunctionDecl *PatternDecl,
+ LocalInstantiationScope &Scope,
+ const MultiLevelTemplateArgumentList &TemplateArgs) {
+ if (Function)
+ return ::addInstantiatedParametersToScope(*this, Function->parameters(),
+ PatternDecl, Scope, TemplateArgs);
+ FunctionTypeLoc TypeLoc = PatternDecl->getFunctionTypeLoc();
+ assert(!TypeLoc.isNull() && "Invalid function TypeLoc?");
+ SmallVector<QualType> ParamTypes;
+ SmallVector<ParmVarDecl *> OutParams;
+ Sema::ExtParameterInfoBuilder ExtParamInfos;
+ if (SubstParmTypes(PatternDecl->getLocation(), TypeLoc.getParams(), nullptr,
+ TemplateArgs, ParamTypes, &OutParams, ExtParamInfos))
+ return true;
+ return ::addInstantiatedParametersToScope(*this, OutParams, PatternDecl,
+ Scope, TemplateArgs);
+}
+
bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
ParmVarDecl *Param) {
assert(Param->hasUninstantiatedDefaultArg());
>From 3aa27cce0f4c57b568a117040b0067e9a39819f6 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Mon, 12 Aug 2024 15:22:42 +0800
Subject: [PATCH 2/2] Rectify diagnostics
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 32 ++++++++-----------
clang/lib/Sema/SemaTemplateDeductionGuide.cpp | 8 +++--
clang/test/CXX/drs/cwg23xx.cpp | 32 +++++++++++++++++++
clang/test/CXX/drs/cwg26xx.cpp | 2 +-
.../expr.prim.req/nested-requirement.cpp | 2 +-
.../constrant-satisfaction-conversions.cpp | 6 ++--
.../SemaCXX/concept-crash-on-diagnostic.cpp | 2 +-
clang/test/SemaCXX/cxx20-ctad-type-alias.cpp | 2 +-
clang/test/SemaCXX/cxx23-assume.cpp | 6 ++--
clang/test/SemaCXX/cxx2c-fold-exprs.cpp | 2 +-
clang/test/SemaCXX/lambda-unevaluated.cpp | 4 +--
.../SemaTemplate/concepts-recursive-inst.cpp | 4 +--
.../SemaTemplate/cxx2a-constraint-exprs.cpp | 2 +-
clang/test/SemaTemplate/deduction-guide.cpp | 5 ---
.../nested-implicit-deduction-guides.cpp | 8 +++--
15 files changed, 72 insertions(+), 45 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 1880104625e4cb..04904ce06c49a8 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3863,7 +3863,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
FD = const_cast<FunctionDecl *>(FDFriend);
Owner = FD->getLexicalDeclContext();
}
-#if 1
+ // [DR2369]
// FIXME: We have to partially instantiate lambda's captures for constraint
// evaluation.
if (!isLambdaCallOperator(FD) && !isLambdaConversionOperator(FD) &&
@@ -3894,9 +3894,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
/*SkipForSpecialization=*/false,
/*Merged=*/&MLTAL);
- // if (SetupConstraintScope(FD, SugaredBuilder, MLTAL, Scope))
- // return TemplateDeductionResult::MiscellaneousDeductionFailure;
-
MultiLevelTemplateArgumentList JustTemplArgs(
Template, CanonicalDeducedArgumentList->asArray(),
/*Final=*/false);
@@ -3921,7 +3918,7 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr);
llvm::SmallVector<Expr *, 1> Converted;
if (CheckConstraintSatisfaction(Template, TemplateAC, MLTAL,
- Template->getSourceRange(),
+ Info.getLocation(),
Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
@@ -3931,7 +3928,18 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
}
}
}
-#endif
+
+ // C++ [temp.deduct.call]p10: [DR1391]
+ // If deduction succeeds for all parameters that contain
+ // template-parameters that participate in template argument deduction,
+ // and all template arguments are explicitly specified, deduced, or
+ // obtained from default template arguments, remaining parameters are then
+ // compared with the corresponding arguments. For each remaining parameter
+ // P with a type that was non-dependent before substitution of any
+ // explicitly-specified template arguments, if the corresponding argument
+ // A cannot be implicitly converted to P, deduction fails.
+ if (CheckNonDependent())
+ return TemplateDeductionResult::NonDependentConversionFailure;
MultiLevelTemplateArgumentList SubstArgs(
FunctionTemplate, CanonicalDeducedArgumentList->asArray(),
@@ -3982,18 +3990,6 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
}
}
- // C++ [temp.deduct.call]p10: [DR1391]
- // If deduction succeeds for all parameters that contain
- // template-parameters that participate in template argument deduction,
- // and all template arguments are explicitly specified, deduced, or
- // obtained from default template arguments, remaining parameters are then
- // compared with the corresponding arguments. For each remaining parameter
- // P with a type that was non-dependent before substitution of any
- // explicitly-specified template arguments, if the corresponding argument
- // A cannot be implicitly converted to P, deduction fails.
- if (CheckNonDependent())
- return TemplateDeductionResult::NonDependentConversionFailure;
-
// We skipped the instantiation of the explicit-specifier during the
// substitution of `FD` before. So, we try to instantiate it back if
// `Specialization` is either a constructor or a conversion function.
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index 545da21183c3c4..405a733550fd54 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -904,10 +904,12 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
Context.getTrivialTypeSourceInfo(
Context.getDeducedTemplateSpecializationType(
TemplateName(AliasTemplate), /*DeducedType=*/QualType(),
- /*IsDependent=*/true)), // template specialization type whose
- // arguments will be deduced.
+ /*IsDependent=*/true),
+ AliasTemplate->getLocation()), // template specialization type whose
+ // arguments will be deduced.
Context.getTrivialTypeSourceInfo(
- ReturnType), // type from which template arguments are deduced.
+ ReturnType, AliasTemplate->getLocation()), // type from which template
+ // arguments are deduced.
};
return TypeTraitExpr::Create(
Context, Context.getLogicalOperationType(), AliasTemplate->getLocation(),
diff --git a/clang/test/CXX/drs/cwg23xx.cpp b/clang/test/CXX/drs/cwg23xx.cpp
index e4a1e90941dbf0..4a0131aad1436f 100644
--- a/clang/test/CXX/drs/cwg23xx.cpp
+++ b/clang/test/CXX/drs/cwg23xx.cpp
@@ -392,3 +392,35 @@ namespace cwg2397 { // cwg2397: 17
} // namespace cwg2397
#endif
+
+#if __cplusplus >= 202002L
+
+namespace cwg2369 { // cwg2369: 20
+
+template <class T> struct Z {
+ typedef typename T::x xx;
+};
+
+template <class T>
+concept C = requires { typename T::A; };
+template <C T> typename Z<T>::xx f(void *, T); // #1
+template <class T> void f(int, T); // #2
+
+struct A {
+} a;
+
+struct ZZ {
+ template <class T, class = typename Z<T>::xx> operator T *();
+ operator int();
+};
+
+void foo() {
+ ZZ zz;
+ f(1, a); // OK, deduction fails for #1 because there is no conversion from int
+ // to void*
+ f(zz, 42); // OK, deduction fails for #1 because C<int> is not satisfied
+}
+
+} // namespace cwg2369
+
+#endif
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index d843b09ee075ae..3107c6130b81c4 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -210,7 +210,7 @@ void f(T) requires requires { []() { T::invalid; } (); };
// since-cxx20-note at -3 {{in instantiation of requirement here}}
// since-cxx20-note at -4 {{while substituting template arguments into constraint expression here}}
// since-cxx20-note@#cwg2672-f-0 {{while checking constraint satisfaction for template 'f<int>' required here}}
-// since-cxx20-note@#cwg2672-f-0 {{in instantiation of function template specialization 'cwg2672::f<int>' requested here}}
+// since-cxx20-note@#cwg2672-f-0 {{while substituting deduced template arguments into function template 'f' [with T = int]}}
void f(...);
template <class T>
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
index 00ac9d0422d67e..d7973986185847 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/nested-requirement.cpp
@@ -154,7 +154,7 @@ void func() {
bar<int>();
// expected-note at -1 {{while checking constraint satisfaction for template 'bar<int>' required here}} \
- // expected-note at -1 {{in instantiation of function template specialization}}
+ // expected-note at -1 {{while substituting deduced template arguments into function template 'bar' [with T = int]}}
// expected-note@#bar {{in instantiation of static data member}}
// expected-note@#bar {{in instantiation of requirement here}}
// expected-note@#bar {{while checking the satisfaction of nested requirement requested here}}
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
index ba8e2dc372e984..c41de77986bcae 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.atomic/constrant-satisfaction-conversions.cpp
@@ -11,7 +11,7 @@ template<typename T> struct S {
// expected-error at +3{{atomic constraint must be of type 'bool' (found 'S<int>')}}
// expected-note@#FINST{{while checking constraint satisfaction}}
-// expected-note@#FINST{{in instantiation of function template specialization}}
+// expected-note@#FINST{{while substituting deduced template arguments into function template 'f' [with T = int]}}
template<typename T> requires (S<T>{})
void f(T);
void f(int);
@@ -19,7 +19,7 @@ void f(int);
// Ensure this applies to operator && as well.
// expected-error at +3{{atomic constraint must be of type 'bool' (found 'S<int>')}}
// expected-note@#F2INST{{while checking constraint satisfaction}}
-// expected-note@#F2INST{{in instantiation of function template specialization}}
+// expected-note@#F2INST{{while substituting deduced template arguments into function template 'f2' [with T = int]}}
template<typename T> requires (S<T>{} && true)
void f2(T);
void f2(int);
@@ -32,7 +32,7 @@ template<typename T> requires requires {
// expected-note at -4{{while checking the satisfaction}}
// expected-note at -6{{while substituting template arguments}}
// expected-note@#F3INST{{while checking constraint satisfaction}}
- // expected-note@#F3INST{{in instantiation of function template specialization}}
+ // expected-note@#F3INST{{while substituting deduced template arguments into function template 'f3' [with T = int]}}
//
}
void f3(T);
diff --git a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
index 71e55c8290ee4a..ccc109cbca0f19 100644
--- a/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
+++ b/clang/test/SemaCXX/concept-crash-on-diagnostic.cpp
@@ -31,7 +31,7 @@ void function() {
// expected-note@#3 {{checking the satisfaction of concept 'convertible_to<bool, bool>'}}
// expected-note@#2 {{substituting template arguments into constraint expression here}}
// expected-note@#5 {{checking constraint satisfaction for template 'compare<Object *, Object *>'}}
-// expected-note@#5 {{in instantiation of function template specialization 'compare<Object *, Object *>' requested here}}
+// expected-note@#5 {{while substituting deduced template arguments into function template 'compare' [with IteratorL = Object *, IteratorR = Object *]}}
// expected-note@#4 {{candidate template ignored: constraints not satisfied [with IteratorL = Object *, IteratorR = Object *]}}
// We don't know exactly the substituted type for `lhs == rhs`, thus a placeholder 'expr-type' is emitted.
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index 5392573fcdb9d5..dff7f611635582 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -196,7 +196,7 @@ struct Foo {
template <int K>
using Bar = Foo<double, K>; // expected-note {{constraints not satisfied for class template 'Foo'}}
-// expected-note at -1 {{candidate template ignored: could not match}}
+// expected-note at -1 {{candidate template ignored: could not match}} expected-note at -1 {{candidate template ignored: constraints not satisfied}}
// expected-note at -2 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(Foo<double, K>) -> Foo<double, K>'}}
// expected-note at -3 {{implicit deduction guide declared as 'template <int K> requires __is_deducible(test14::Bar, Foo<double, K>) Bar(const double (&)[K]) -> Foo<double, K>'}}
double abc[3];
diff --git a/clang/test/SemaCXX/cxx23-assume.cpp b/clang/test/SemaCXX/cxx23-assume.cpp
index 9138501d726dd6..35971a58331ff3 100644
--- a/clang/test/SemaCXX/cxx23-assume.cpp
+++ b/clang/test/SemaCXX/cxx23-assume.cpp
@@ -127,12 +127,12 @@ constexpr int f5() requires (!C<T>) { return 2; } // expected-note 4 {{while che
static_assert(f5<int>() == 1);
static_assert(f5<D>() == 1); // expected-note 3 {{while checking constraint satisfaction}}
- // expected-note at -1 3 {{in instantiation of}}
+ // expected-note at -1 3 {{while substituting deduced template arguments}}
// expected-error at -2 {{no matching function for call}}
static_assert(f5<double>() == 2);
-static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
-static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{in instantiation of}}
+static_assert(f5<E>() == 1); // expected-note {{while checking constraint satisfaction}} expected-note {{while substituting deduced template arguments}}
+static_assert(f5<F>() == 2); // expected-note {{while checking constraint satisfaction}} expected-note {{while substituting deduced template arguments}}
// Do not validate assumptions whose evaluation would have side-effects.
constexpr int foo() {
diff --git a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
index 0674135aac483f..70644e3aef8a71 100644
--- a/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
+++ b/clang/test/SemaCXX/cxx2c-fold-exprs.cpp
@@ -233,7 +233,7 @@ void g() {
A<Thingy, Thingy> *ap;
f(ap, ap); // expected-error{{no matching function for call to 'f'}} \
// expected-note {{while checking constraint satisfaction}} \
- // expected-note {{in instantiation of function template specialization}}
+ // expected-note {{while substituting deduced template arguments}}
}
}
diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp
index 39ee89bc797f84..242d1fc0c1219d 100644
--- a/clang/test/SemaCXX/lambda-unevaluated.cpp
+++ b/clang/test/SemaCXX/lambda-unevaluated.cpp
@@ -172,7 +172,7 @@ int* func(T) requires requires { []() { T::foo(); }; }; // expected-error{{type
double* func(...);
static_assert(__is_same(decltype(func(0)), double*)); // expected-note {{while checking constraint satisfaction for template 'func<int>' required here}}
- // expected-note at -1 {{in instantiation of function template specialization 'lambda_in_constraints::func<int>'}}
+ // expected-note at -1 {{while substituting deduced template arguments into function template 'func' [with T = int]}}
static_assert(__is_same(decltype(func(WithFoo())), int*));
template <class T>
@@ -250,7 +250,7 @@ S s("a"); // #use
// expected-note@#S-requires {{substituting template arguments into constraint expression here}}
// expected-note@#S-requires {{in instantiation of requirement here}}
// expected-note@#use {{checking constraint satisfaction for template 'S<const char *>' required here}}
-// expected-note@#use {{requested here}}
+// expected-note@#use {{while substituting deduced template arguments into function template 'S' [with value:auto = const char *]}}
// expected-note-re@#S 2{{candidate constructor {{.*}} not viable}}
// expected-note@#S-ctor {{constraints not satisfied}}
// expected-note-re@#S-requires {{because {{.*}} would be invalid}}
diff --git a/clang/test/SemaTemplate/concepts-recursive-inst.cpp b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
index 8ac5a0e753a340..c5381c376602b5 100644
--- a/clang/test/SemaTemplate/concepts-recursive-inst.cpp
+++ b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
@@ -76,7 +76,7 @@ auto it = begin(rng); // #BEGIN_CALL
// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<struct my_range>' requested here}}
// expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
// expected-note@#BEGIN_CALL {{while checking constraint satisfaction for template 'begin<struct my_range>' required here}}
-// expected-note@#BEGIN_CALL {{in instantiation of function template specialization}}
+// expected-note@#BEGIN_CALL {{while substituting deduced template arguments into function template}}
// Fallout of the failure is failed lookup, which is necessary to stop odd
// cascading errors.
@@ -103,7 +103,7 @@ namespace GH50891 {
// expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
// expected-note@#OP_TO {{while substituting template arguments into constraint expression here}}
// expected-note@#FOO_CALL {{while checking constraint satisfaction for template}}
- // expected-note@#FOO_CALL {{in instantiation of function template specialization}}
+ // expected-note@#FOO_CALL {{while substituting deduced template arguments into function template}}
// expected-note@#FOO_CALL {{in instantiation of requirement here}}
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
diff --git a/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp b/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp
index f4403587a62594..5809ef684bbf3b 100644
--- a/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp
+++ b/clang/test/SemaTemplate/cxx2a-constraint-exprs.cpp
@@ -34,7 +34,7 @@ namespace constant_evaluated {
expected-note at -1{{candidate template ignored}}
int a = (foo<int>(), 0);
// expected-note at -1 {{while checking}} expected-error at -1{{no matching function}} \
- expected-note at -1 {{in instantiation}}
+ expected-note at -1 {{while substituting}}
template<typename T> void bar() requires requires { requires f<int[2]>; } { };
// expected-note at -1{{in instantiation}} \
expected-note at -1{{while substituting}} \
diff --git a/clang/test/SemaTemplate/deduction-guide.cpp b/clang/test/SemaTemplate/deduction-guide.cpp
index d03c783313dd71..67d00bb49f77d7 100644
--- a/clang/test/SemaTemplate/deduction-guide.cpp
+++ b/clang/test/SemaTemplate/deduction-guide.cpp
@@ -234,11 +234,6 @@ F s(0);
// CHECK: | `-CXXBoolLiteralExpr {{.*}} 'bool' false
// CHECK: |-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (U) -> F<>'
// CHECK: | `-ParmVarDecl {{.*}} 'U'
-// CHECK: `-CXXDeductionGuideDecl {{.*}} implicit <deduction guide for F> 'auto (int) -> F<>'
-// CHECK: |-TemplateArgument integral ''x''
-// CHECK: |-TemplateArgument type 'int'
-// CHECK: | `-BuiltinType {{.*}} 'int'
-// CHECK: `-ParmVarDecl {{.*}} 'int'
// CHECK: FunctionProtoType {{.*}} 'auto (U) -> F<>' dependent trailing_return cdecl
// CHECK: |-InjectedClassNameType {{.*}} 'F<>' dependent
// CHECK: | `-CXXRecord {{.*}} 'F'
diff --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
index af3e3358f61382..5c7a90273d0e0f 100644
--- a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
@@ -38,7 +38,7 @@ template<typename A, typename T>
concept True = true;
template<typename T>
-concept False = false;
+concept False = false; // #False
template<class X> struct concepts {
template<class Y> struct B {
@@ -68,7 +68,7 @@ template<typename X> struct nested_init_list {
Y y;
};
- template<False F>
+ template<False F> // #INIT_LIST_INNER_INVALID_HEADER
struct concept_fail { // #INIT_LIST_INNER_INVALID
X x;
F f;
@@ -81,7 +81,9 @@ using NIL = nested_init_list<int>::B<int>;
// expected-error at +1 {{no viable constructor or deduction guide for deduction of template arguments of 'nested_init_list<int>::concept_fail'}}
nested_init_list<int>::concept_fail nil_invalid{1, ""};
-// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
+// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: constraints not satisfied [with F = const char *]}}
+// expected-note@#INIT_LIST_INNER_INVALID_HEADER {{because 'const char *' does not satisfy 'False'}}
+// expected-note@#False {{because 'false' evaluated to false}}
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(int, F) -> concept_fail<F>'}}
// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
// expected-note@#INIT_LIST_INNER_INVALID {{implicit deduction guide declared as 'template <False F> concept_fail(concept_fail<F>) -> concept_fail<F>'}}
More information about the cfe-commits
mailing list