[llvm-branch-commits] [clang] [libcxx] [clang] Reland: Instantiate concepts with sugared template arguments (PR #101782)
Matheus Izvekov via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Aug 2 19:25:06 PDT 2024
https://github.com/mizvekov created https://github.com/llvm/llvm-project/pull/101782
Since we don't unique specializations for concepts, we can just instantiate them with the sugared template arguments, at negligible cost.
If we don't track their specializations, we can't resugar them later anyway, and that would be more expensive than just instantiating them sugared in the first place since it would require an additional pass.
This was a previously reverted patch due to a performance regression, which was very simple to fix, as we were only missing the canonicalizations for the key to the satisfcation cache.
Fixes #59271
Differential Revision: https://reviews.llvm.org/D136566
>From d566dbe3b037c153994cb073a46aa283e333cca5 Mon Sep 17 00:00:00 2001
From: Matheus Izvekov <mizvekov at gmail.com>
Date: Sun, 23 Oct 2022 11:37:20 +0200
Subject: [PATCH] [clang] Reland: Instantiate concepts with sugared template
arguments
Since we don't unique specializations for concepts, we can just instantiate
them with the sugared template arguments, at negligible cost.
If we don't track their specializations, we can't resugar them later
anyway, and that would be more expensive than just instantiating them
sugared in the first place since it would require an additional pass.
This was a previously reverted patch due to a performance regression,
which was very simple to fix, as we were only missing the
canonicalizations for the key to the satisfcation cache.
Fixes #59271
Differential Revision: https://reviews.llvm.org/D136566
---
clang/docs/ReleaseNotes.rst | 1 +
clang/include/clang/Sema/Template.h | 6 +++---
clang/lib/Sema/SemaConcept.cpp | 11 +++++++----
clang/lib/Sema/SemaExprCXX.cpp | 5 ++---
clang/lib/Sema/SemaTemplate.cpp | 10 +++++-----
clang/lib/Sema/SemaTemplateDeduction.cpp | 16 ++++++++--------
clang/lib/Serialization/ASTReaderDecl.cpp | 2 +-
clang/test/AST/ast-dump-concepts.cpp | 10 ++++++----
.../expr.prim.req/compound-requirement.cpp | 10 +++++-----
.../expr.prim.req/nested-requirement.cpp | 2 +-
.../expr.prim.req/simple-requirement.cpp | 4 ++--
.../expr.prim/expr.prim.req/type-requirement.cpp | 12 ++++++------
.../temp/temp.constr/temp.constr.normal/p1.cpp | 2 +-
clang/test/CXX/temp/temp.param/p10-2a.cpp | 4 ++--
.../SemaTemplate/concepts-recursive-inst.cpp | 12 ++++++------
clang/test/SemaTemplate/concepts.cpp | 4 ++--
.../SemaTemplate/instantiate-requires-expr.cpp | 16 +++++++++++++---
clang/test/SemaTemplate/pr52970.cpp | 2 +-
.../cpp17_iterator_concepts.verify.cpp | 2 +-
19 files changed, 73 insertions(+), 58 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 34aa4c73796ed..0889410476d53 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -144,6 +144,7 @@ Improvements to Clang's diagnostics
- Clang now diagnoses undefined behavior in constant expressions more consistently. This includes invalid shifts, and signed overflow in arithmetic.
- -Wdangling-assignment-gsl is enabled by default.
+- Clang now does a better job preserving the type as written when specializing concepts.
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h
index 0340c23fd170d..d616865afe807 100644
--- a/clang/include/clang/Sema/Template.h
+++ b/clang/include/clang/Sema/Template.h
@@ -234,7 +234,8 @@ enum class TemplateSubstitutionKind : char {
/// Replaces the current 'innermost' level with the provided argument list.
/// This is useful for type deduction cases where we need to get the entire
/// list from the AST, but then add the deduced innermost list.
- void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args) {
+ void replaceInnermostTemplateArguments(Decl *AssociatedDecl, ArgList Args,
+ bool Final = false) {
assert((!TemplateArgumentLists.empty() || NumRetainedOuterLevels) &&
"Replacing in an empty list?");
@@ -246,8 +247,7 @@ enum class TemplateSubstitutionKind : char {
TemplateArgumentLists[0].Args = Args;
} else {
--NumRetainedOuterLevels;
- TemplateArgumentLists.push_back(
- {{AssociatedDecl, /*Final=*/false}, Args});
+ TemplateArgumentLists.push_back({{AssociatedDecl, Final}, Args});
}
}
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 7d7a94e9fd637..75ccefa2a487e 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -414,7 +414,8 @@ DiagRecursiveConstraintEval(Sema &S, llvm::FoldingSetNodeID &ID,
E->Profile(ID, S.Context, /*Canonical=*/true);
for (const auto &List : MLTAL)
for (const auto &TemplateArg : List.Args)
- TemplateArg.Profile(ID, S.Context);
+ S.Context.getCanonicalTemplateArgument(TemplateArg)
+ .Profile(ID, S.Context);
// Note that we have to do this with our own collection, because there are
// times where a constraint-expression check can cause us to need to evaluate
@@ -638,8 +639,8 @@ bool Sema::CheckConstraintSatisfaction(
// here.
llvm::SmallVector<TemplateArgument, 4> FlattenedArgs;
for (auto List : TemplateArgsLists)
- FlattenedArgs.insert(FlattenedArgs.end(), List.Args.begin(),
- List.Args.end());
+ for (const TemplateArgument &Arg : List.Args)
+ FlattenedArgs.emplace_back(Context.getCanonicalTemplateArgument(Arg));
llvm::FoldingSetNodeID ID;
ConstraintSatisfaction::Profile(ID, Context, Template, FlattenedArgs);
@@ -823,6 +824,8 @@ Sema::SetupConstraintCheckingTemplateArgumentsAndScope(
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
+ if (TemplateArgs)
+ MLTAL.replaceInnermostTemplateArguments(FD, *TemplateArgs, /*Final=*/true);
if (SetupConstraintScope(FD, TemplateArgs, MLTAL, Scope))
return std::nullopt;
@@ -1476,7 +1479,7 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N,
const ConceptSpecializationExpr *CSE) {
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
CSE->getNamedConcept(), CSE->getNamedConcept()->getLexicalDeclContext(),
- /*Final=*/false, CSE->getTemplateArguments(),
+ /*Final=*/true, CSE->getTemplateArguments(),
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConstraintInstantiation=*/true);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index c5003d9ac0254..cabe8a8382f5a 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -9333,14 +9333,13 @@ Sema::BuildExprRequirement(
// be satisfied.
TemplateParameterList *TPL =
ReturnTypeRequirement.getTypeConstraintTemplateParameterList();
- QualType MatchedType =
- Context.getReferenceQualifiedType(E).getCanonicalType();
+ QualType MatchedType = Context.getReferenceQualifiedType(E);
llvm::SmallVector<TemplateArgument, 1> Args;
Args.push_back(TemplateArgument(MatchedType));
auto *Param = cast<TemplateTypeParmDecl>(TPL->getParam(0));
- MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/false);
+ MultiLevelTemplateArgumentList MLTAL(Param, Args, /*Final=*/true);
MLTAL.addOuterRetainedLevels(TPL->getDepth());
const TypeConstraint *TC = Param->getTypeConstraint();
assert(TC && "Type Constraint cannot be null here");
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index cb16e8caa9a8a..720862ec0bffa 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4358,13 +4358,13 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
auto *CSD = ImplicitConceptSpecializationDecl::Create(
Context, NamedConcept->getDeclContext(), NamedConcept->getLocation(),
- CanonicalConverted);
+ SugaredConverted);
ConstraintSatisfaction Satisfaction;
bool AreArgsDependent =
TemplateSpecializationType::anyDependentTemplateArguments(
- *TemplateArgs, CanonicalConverted);
- MultiLevelTemplateArgumentList MLTAL(NamedConcept, CanonicalConverted,
- /*Final=*/false);
+ *TemplateArgs, SugaredConverted);
+ MultiLevelTemplateArgumentList MLTAL(NamedConcept, SugaredConverted,
+ /*Final=*/true);
LocalInstantiationScope Scope(*this);
EnterExpressionEvaluationContext EECtx{
@@ -5582,7 +5582,7 @@ bool Sema::CheckTemplateArgumentList(
CXXThisScopeRAII(*this, RD, ThisQuals, RD != nullptr);
MultiLevelTemplateArgumentList MLTAL = getTemplateInstantiationArgs(
- Template, NewContext, /*Final=*/false, CanonicalConverted,
+ Template, NewContext, /*Final=*/true, SugaredConverted,
/*RelativeToPrimary=*/true,
/*Pattern=*/nullptr,
/*ForConceptInstantiation=*/true);
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index eeeb780299e78..63e1dd581c2d0 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3078,7 +3078,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
// If we don't need to replace the deduced template arguments,
// we can add them immediately as the inner-most argument list.
if (!DeducedArgsNeedReplacement(Template))
- Innermost = CanonicalDeducedArgs;
+ Innermost = SugaredDeducedArgs;
MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs(
Template, Template->getDeclContext(), /*Final=*/false, Innermost,
@@ -3090,7 +3090,7 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template,
// not class-scope explicit specialization, so replace with Deduced Args
// instead of adding to inner-most.
if (!Innermost)
- MLTAL.replaceInnermostTemplateArguments(Template, CanonicalDeducedArgs);
+ MLTAL.replaceInnermostTemplateArguments(Template, SugaredDeducedArgs);
if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, MLTAL,
Info.getLocation(),
@@ -3913,13 +3913,13 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
(CanonicalBuilder.size() ==
FunctionTemplate->getTemplateParameters()->size())) {
if (CheckInstantiatedFunctionTemplateConstraints(
- Info.getLocation(), Specialization, CanonicalBuilder,
+ Info.getLocation(), Specialization, SugaredBuilder,
Info.AssociatedConstraintsSatisfaction))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) {
- Info.reset(Info.takeSugared(),
- TemplateArgumentList::CreateCopy(Context, CanonicalBuilder));
+ Info.reset(TemplateArgumentList::CreateCopy(Context, SugaredBuilder),
+ Info.takeCanonical());
return TemplateDeductionResult::ConstraintsNotSatisfied;
}
}
@@ -4992,8 +4992,8 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
/*PartialTemplateArgs=*/false,
SugaredConverted, CanonicalConverted))
return true;
- MultiLevelTemplateArgumentList MLTAL(Concept, CanonicalConverted,
- /*Final=*/false);
+ MultiLevelTemplateArgumentList MLTAL(Concept, SugaredConverted,
+ /*Final=*/true);
// Build up an EvaluationContext with an ImplicitConceptSpecializationDecl so
// that the template arguments of the constraint can be preserved. For
// example:
@@ -5007,7 +5007,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type,
S, Sema::ExpressionEvaluationContext::Unevaluated,
ImplicitConceptSpecializationDecl::Create(
S.getASTContext(), Concept->getDeclContext(), Concept->getLocation(),
- CanonicalConverted));
+ SugaredConverted));
if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()},
MLTAL, TypeLoc.getLocalSourceRange(),
Satisfaction))
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 31ab6c651d59f..0ced5f9290408 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2391,7 +2391,7 @@ void ASTDeclReader::VisitImplicitConceptSpecializationDecl(
VisitDecl(D);
llvm::SmallVector<TemplateArgument, 4> Args;
for (unsigned I = 0; I < D->NumTemplateArgs; ++I)
- Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/true));
+ Args.push_back(Record.readTemplateArgument(/*Canonicalize=*/false));
D->setTemplateArguments(Args);
}
diff --git a/clang/test/AST/ast-dump-concepts.cpp b/clang/test/AST/ast-dump-concepts.cpp
index a5e0673c241ef..4b8e9026b2916 100644
--- a/clang/test/AST/ast-dump-concepts.cpp
+++ b/clang/test/AST/ast-dump-concepts.cpp
@@ -20,8 +20,9 @@ struct Foo {
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'binary_concept'
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13, col:31> 'bool' Concept {{.*}} 'binary_concept'
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:13:9> col:9
- // CHECK-NEXT: | |-TemplateArgument type 'type-parameter-1-0'
- // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
+ // CHECK-NEXT: | |-TemplateArgument type 'R'
+ // CHECK-NEXT: | | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
+ // CHECK-NEXT: | | `-TemplateTypeParm {{.*}} 'R'
// CHECK-NEXT: | `-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType {{.*}} 'int'
// CHECK-NEXT: |-TemplateArgument {{.*}} type 'R'
@@ -35,8 +36,9 @@ struct Foo {
// CHECK: TemplateTypeParmDecl {{.*}} referenced Concept {{.*}} 'unary_concept'
// CHECK-NEXT: `-ConceptSpecializationExpr {{.*}} <col:13> 'bool'
// CHECK-NEXT: |-ImplicitConceptSpecializationDecl {{.*}} <line:10:9> col:9
- // CHECK-NEXT: | `-TemplateArgument type 'type-parameter-1-0'
- // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'type-parameter-1-0' dependent {{.*}}depth 1 index 0
+ // CHECK-NEXT: | `-TemplateArgument type 'R'
+ // CHECK-NEXT: | `-TemplateTypeParmType {{.*}} 'R' dependent {{.*}}depth 1 index 0
+ // CHECK-NEXT: | `-TemplateTypeParm {{.*}} 'R'
template <unary_concept R>
Foo(R);
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
index dc0e84280e056..3d6f0b11fa99c 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/compound-requirement.cpp
@@ -35,14 +35,14 @@ using r2i2 = r2<A>; // expected-error{{constraints not satisfied for class templ
using r2i3 = r2<D>;
using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class template 'r2' [with T = const D]}}
-template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
+template<typename T> requires requires { { sizeof(T) }; } // expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}} expected-note{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
struct r3 {};
using r3i1 = r3<int>;
using r3i2 = r3<A>;
using r3i3 = r3<A &>;
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
-using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
+using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
// Non-dependent expressions
@@ -149,7 +149,7 @@ namespace std_example {
template<typename T> constexpr bool is_same_v<T, T> = true;
template<typename T, typename U> concept same_as = is_same_v<T, U>;
- // expected-note at -1 {{because 'is_same_v<int, int *>' evaluated to false}}
+ // expected-note at -1 {{because 'is_same_v<int, typename T2::inner>' evaluated to false}}
static_assert(C1<int>);
static_assert(C1<int*>);
@@ -173,9 +173,9 @@ namespace std_example {
int operator *() { return 0; }
};
static_assert(C2<T1>);
- template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'std_example::T2' does not satisfy 'C2'}}
+ template<C2 T> struct C2_check {}; // expected-note{{because 'int' does not satisfy 'C2'}} expected-note{{because 'T2' does not satisfy 'C2'}}
using c2c1 = C2_check<int>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = int]}}
- using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::T2]}}
+ using c2c2 = C2_check<T2>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = T2]}}
template<typename T>
void g(T t) noexcept(sizeof(T) == 1) {}
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 763d983d20f61..00ac9d0422d67 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
@@ -27,7 +27,7 @@ using r4i = X<void>::r4<int>; // expected-error{{constraints not satisfied for c
// C++ [expr.prim.req.nested] Examples
namespace std_example {
- template<typename U> concept C1 = sizeof(U) == 1; // expected-note{{because 'sizeof(int) == 1' (4 == 1) evaluated to false}}
+ template<typename U> concept C1 = sizeof(U) == 1; // expected-note{{because 'sizeof(decltype(+t)) == 1' (4 == 1) evaluated to false}}
template<typename T> concept D =
requires (T t) {
requires C1<decltype (+t)>; // expected-note{{because 'decltype(+t)' (aka 'int') does not satisfy 'C1'}}
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
index 7515f5c62d5ea..abfadfa348841 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/simple-requirement.cpp
@@ -39,14 +39,14 @@ using r2i4 = r2<const D>; // expected-error{{constraints not satisfied for class
template<typename T> requires requires { sizeof(T); }
// expected-note at -1{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'void'}}
-// expected-note at -2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'nonexistent'}}
+// expected-note at -2{{because 'sizeof(T)' would be invalid: invalid application of 'sizeof' to an incomplete type 'class nonexistent'}}
struct r3 {};
using r3i1 = r3<int>;
using r3i2 = r3<A>;
using r3i3 = r3<A &>;
using r3i4 = r3<void>; // expected-error{{constraints not satisfied for class template 'r3' [with T = void]}}
-using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = nonexistent]}}
+using r3i4 = r3<class nonexistent>; // expected-error{{constraints not satisfied for class template 'r3' [with T = class nonexistent]}}
template<typename T> requires requires (T t) { 0; "a"; (void)'a'; }
struct r4 {};
diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
index 5433cfb21955d..28dff336d053c 100644
--- a/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
+++ b/clang/test/CXX/expr/expr.prim/expr.prim.req/type-requirement.cpp
@@ -182,14 +182,14 @@ namespace std_example {
static_assert(C1<has_inner_and_type> && C2<has_inner_and_type> && C3<has_inner_and_type>);
template<C1 T> struct C1_check {};
// expected-note at -1 {{because 'int' does not satisfy 'C1'}}
- // expected-note at -2 {{because 'std_example::has_type' does not satisfy 'C1'}}
+ // expected-note at -2 {{because 'has_type' does not satisfy 'C1'}}
template<C2 T> struct C2_check {};
- // expected-note at -1 {{because 'std_example::has_inner' does not satisfy 'C2'}}
+ // expected-note at -1 {{because 'has_inner' does not satisfy 'C2'}}
template<C3 T> struct C3_check {};
// expected-note at -1 {{because 'void' does not satisfy 'C3'}}
using c1 = C1_check<int>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = int]}}
- using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = std_example::has_type]}}
- using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = std_example::has_inner]}}
+ using c2 = C1_check<has_type>; // expected-error{{constraints not satisfied for class template 'C1_check' [with T = has_type]}}
+ using c3 = C2_check<has_inner>; // expected-error{{constraints not satisfied for class template 'C2_check' [with T = has_inner]}}
using c4 = C3_check<void>; // expected-error{{constraints not satisfied for class template 'C3_check' [with T = void]}}
}
@@ -199,10 +199,10 @@ template <typename T> concept C = requires { requires requires { T::a; }; };
// expected-note at -1 {{because 'T::a' would be invalid: no member named 'a' in 'PR48656::T1'}}
template <C...> struct A {};
-// expected-note at -1 {{because 'PR48656::T1' does not satisfy 'C'}}
+// expected-note at -1 {{because 'T1' does not satisfy 'C'}}
struct T1 {};
-template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <PR48656::T1>]}}
+template struct A<T1>; // expected-error {{constraints not satisfied for class template 'A' [with $0 = <T1>]}}
struct T2 { static constexpr bool a = false; };
template struct A<T2>;
diff --git a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
index d80710937cdfa..02c97b4591a15 100644
--- a/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
+++ b/clang/test/CXX/temp/temp.constr/temp.constr.normal/p1.cpp
@@ -8,7 +8,7 @@ template<typename T> requires Bar<T> && true struct S<T> { };
template<typename T> concept True2 = sizeof(T) >= 0;
template<typename T> concept Foo2 = True2<T*>;
-// expected-error at -1{{'type name' declared as a pointer to a reference of type 'type-parameter-0-0 &'}}
+// expected-error at -1{{'type name' declared as a pointer to a reference of type 'T &'}}
template<typename T> concept Bar2 = Foo2<T&>;
// expected-note at -1{{while substituting into concept arguments here; substitution failures not allowed in concept arguments}}
template<typename T> requires Bar2<T> struct S2 { };
diff --git a/clang/test/CXX/temp/temp.param/p10-2a.cpp b/clang/test/CXX/temp/temp.param/p10-2a.cpp
index 4f5fdd3b4809a..97e0ef35837b1 100644
--- a/clang/test/CXX/temp/temp.param/p10-2a.cpp
+++ b/clang/test/CXX/temp/temp.param/p10-2a.cpp
@@ -94,8 +94,8 @@ concept OneOf = (is_same_v<T, Ts> || ...);
// expected-note at -5 {{and 'is_same_v<short, char>' evaluated to false}}
// expected-note at -6 3{{because 'is_same_v<int, char[1]>' evaluated to false}}
// expected-note at -7 3{{and 'is_same_v<int, char[2]>' evaluated to false}}
-// expected-note at -8 2{{because 'is_same_v<std::nullptr_t, char>' evaluated to false}}
-// expected-note at -9 2{{and 'is_same_v<std::nullptr_t, int>' evaluated to false}}
+// expected-note at -8 2{{because 'is_same_v<decltype(nullptr), char>' evaluated to false}}
+// expected-note at -9 2{{and 'is_same_v<decltype(nullptr), int>' evaluated to false}}
template<OneOf<char[1], char[2]> T, OneOf<int, long, char> U>
// expected-note at -1 2{{because 'OneOf<char, char[1], char[2]>' evaluated to false}}
diff --git a/clang/test/SemaTemplate/concepts-recursive-inst.cpp b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
index 9330df8cdd039..8ac5a0e753a34 100644
--- a/clang/test/SemaTemplate/concepts-recursive-inst.cpp
+++ b/clang/test/SemaTemplate/concepts-recursive-inst.cpp
@@ -12,7 +12,7 @@ void g() {
// expected-note@#FDEF{{because 'int' does not satisfy 'c'}}
// expected-note@#CDEF{{because 'f(t)' would be invalid: no matching function for call to 'f'}}
}
-} // namespace GH53213
+} // namespace GH53213
namespace GH45736 {
struct constrained;
@@ -69,13 +69,13 @@ void baz() {
auto it = begin(rng); // #BEGIN_CALL
// expected-error@#INF_BEGIN {{satisfaction of constraint 'Inf<Inf auto>' depends on itself}}
// expected-note@#INF_BEGIN {{while substituting template arguments into constraint expression here}}
-// expected-note@#INF_BEGIN_EXPR {{while checking constraint satisfaction for template 'begin<DirectRecursiveCheck::my_range>' required here}}
+// expected-note@#INF_BEGIN_EXPR {{while checking constraint satisfaction for template 'begin<struct my_range>' required here}}
// expected-note@#INF_BEGIN_EXPR {{while substituting deduced template arguments into function template 'begin'}}
// expected-note@#INF_BEGIN_EXPR {{in instantiation of requirement here}}
// expected-note@#INF_REQ {{while substituting template arguments into constraint expression here}}
-// expected-note@#INF_BEGIN {{while checking the satisfaction of concept 'Inf<DirectRecursiveCheck::my_range>' requested here}}
+// 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<DirectRecursiveCheck::my_range>' required 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}}
// Fallout of the failure is failed lookup, which is necessary to stop odd
@@ -100,7 +100,7 @@ namespace GH50891 {
static_assert(Numeric<Deferred>); // #STATIC_ASSERT
// expected-error@#NUMERIC{{satisfaction of constraint 'requires (T a) { foo(a); }' depends on itself}}
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
- // expected-note@#OP_TO {{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
+ // 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}}
@@ -108,7 +108,7 @@ namespace GH50891 {
// expected-note@#NUMERIC {{while substituting template arguments into constraint expression here}}
// expected-error@#STATIC_ASSERT {{static assertion failed}}
- // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<GH50891::Deferred>' requested here}}
+ // expected-note@#STATIC_ASSERT{{while checking the satisfaction of concept 'Numeric<Deferred>' requested here}}
// expected-note@#STATIC_ASSERT{{because substituted constraint expression is ill-formed: constraint depends on a previously diagnosed expression}}
} // namespace GH50891
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index a4b42cad79abd..19b138270eebb 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -836,13 +836,13 @@ struct Parent {
static_assert(Parent<void>::TakesUnary<int, 0>::i == 0);
// expected-error at +3{{constraints not satisfied for class template 'TakesUnary'}}
// expected-note@#UNARY{{because 'decltype(0ULL)' (aka 'unsigned long long') does not satisfy 'C'}}
-// expected-note@#61777_C{{because 'sizeof(unsigned long long) == 4' (8 == 4) evaluated to false}}
+// expected-note@#61777_C{{because 'sizeof(decltype(0ULL)) == 4' (8 == 4) evaluated to false}}
static_assert(Parent<void>::TakesUnary<int, 0uLL>::i == 0);
static_assert(Parent<int>::TakesBinary<int, 0>::i == 0);
// expected-error at +3{{constraints not satisfied for class template 'TakesBinary'}}
// expected-note@#BINARY{{because 'C2<decltype(0ULL), int>' evaluated to false}}
-// expected-note@#61777_C2{{because 'sizeof(unsigned long long) == sizeof(int)' (8 == 4) evaluated to false}}
+// expected-note@#61777_C2{{because 'sizeof(decltype(0ULL)) == sizeof(int)' (8 == 4) evaluated to false}}
static_assert(Parent<int>::TakesBinary<int, 0ULL>::i == 0);
}
diff --git a/clang/test/SemaTemplate/instantiate-requires-expr.cpp b/clang/test/SemaTemplate/instantiate-requires-expr.cpp
index 20a19d731ae16..c5ebeff828295 100644
--- a/clang/test/SemaTemplate/instantiate-requires-expr.cpp
+++ b/clang/test/SemaTemplate/instantiate-requires-expr.cpp
@@ -76,8 +76,8 @@ namespace type_requirement {
// expected-note at -2 {{because 'false_v<requires { typename contains_template<short>::template temp<contains_template<short> >; }>' evaluated to false}}
struct r2 {};
- using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<int>]}}
- using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = type_requirement::contains_template<short>]}}
+ using r2i1 = r2<contains_template<int>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<int>]}}
+ using r2i2 = r2<contains_template<short>>; // expected-error{{constraints not satisfied for class template 'r2' [with T = contains_template<short>]}}
// substitution error occurs, then requires expr is instantiated again
@@ -108,7 +108,7 @@ namespace type_requirement {
// expected-note at -1 {{because 'false_v<requires { <<error-type>>; } && requires { <<error-type>>; }>' evaluated to false}}
struct r7 {};
- using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, type_requirement::A>]}}
+ using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, A>]}}
}
namespace expr_requirement {
@@ -237,3 +237,13 @@ constexpr bool e_v = true;
static_assert(e_v<bool>);
} // namespace GH73885
+
+namespace sugared_instantiation {
+ template <class C1> concept C = requires { C1{}; };
+ template <class D1> concept D = requires { new D1; };
+
+ // Test that 'deduced auto' doesn't get confused with 'undeduced auto'.
+ auto f() { return 0; }
+ static_assert(requires { { f() } -> C; });
+ static_assert(requires { { f() } -> D; });
+} // namespace sugared_instantiation
diff --git a/clang/test/SemaTemplate/pr52970.cpp b/clang/test/SemaTemplate/pr52970.cpp
index 7aac5ee856593..6aabc419bd2b8 100644
--- a/clang/test/SemaTemplate/pr52970.cpp
+++ b/clang/test/SemaTemplate/pr52970.cpp
@@ -53,7 +53,7 @@ static_assert(!DotFollowingPointer::f(Bad{}), "");
#if __cplusplus >= 202002L
template <class T>
concept C = requires(T t) { t.begin(); };
- // cxx20-note at -1 {{because 't.begin()' would be invalid: member reference type 'Holder<Incomplete> *' is a pointer}}
+ // cxx20-note at -1 {{because 't.begin()' would be invalid: member reference type 'Bad' (aka 'Holder<Incomplete> *') is a pointer}}
static_assert(C<Good>);
static_assert(!C<Bad>);
diff --git a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
index 544a9744b7909..9ce97a4d052e1 100644
--- a/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
+++ b/libcxx/test/libcxx/algorithms/cpp17_iterator_concepts.verify.cpp
@@ -143,7 +143,7 @@ void check_forward_iterator_requirements() {
// expected-note@*:* {{because 'not_default_constructible' does not satisfy '__cpp17_default_constructible'}}
_LIBCPP_REQUIRE_CPP17_FORWARD_ITERATOR(postincrement_not_ref, ""); // expected-error {{static assertion failed}}
#ifndef _AIX
- // expected-note@*:* {{because type constraint 'convertible_to<valid_iterator<postincrement_not_ref>::Proxy, const postincrement_not_ref &>' was not satisfied}}
+ // expected-note@*:* {{because type constraint 'convertible_to<Proxy, const postincrement_not_ref &>' was not satisfied}}
#endif
}
More information about the llvm-branch-commits
mailing list