Skip to content

Commit 5aeaabf

Browse files
royjacobsonErich Keane
authored andcommitted
[Concepts] Check constraints for explicit template instantiations
The standard requires[0] member function constraints to be checked when explicitly instantiating classes. This patch adds this constraints check. This issue is tracked as #46029 [1]. Note that there's an related open CWG issue (2421[2]) about what to do when multiple candidates have satisfied constraints. This is particularly an issue because mangling doesn't contain function constraints, and so the following code still ICEs with definition with same mangled name '_ZN1BIiE1fEv' as another definition: template<class T> struct B { int f() requires std::same_as<T, int> { return 0; } int f() requires (std::same_as<T, int> && !std::same_as<T, char>) { return 1; } }; template struct B<int>; Also note that the constraints checking while instantiating *functions* is still not implemented. I started looking at it but It's a bit more complicated. I believe in such a case we have to consider the partial constraints order and potentially choose the best candidate out of the set of multiple valid ones. [0]: https://eel.is/c++draft/temp.explicit#10 [1]: #46029 [2]: https://cplusplus.github.io/CWG/issues/2421.html Differential Revision: https://reviews.llvm.org/D120255
1 parent 3e87719 commit 5aeaabf

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3230,6 +3230,14 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
32303230
if (FunctionDecl *Pattern =
32313231
Function->getInstantiatedFromMemberFunction()) {
32323232

3233+
if (Function->getTrailingRequiresClause()) {
3234+
ConstraintSatisfaction Satisfaction;
3235+
if (CheckFunctionConstraints(Function, Satisfaction) ||
3236+
!Satisfaction.IsSatisfied) {
3237+
continue;
3238+
}
3239+
}
3240+
32333241
if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
32343242
continue;
32353243

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %clang_cc1 -std=c++20 -ast-dump %s | FileCheck %s
2+
3+
namespace PR46029 {
4+
5+
template <int N>
6+
void canary1();
7+
template <int N>
8+
void canary2();
9+
10+
template <int N>
11+
struct A {
12+
void f() requires(N == 1) {
13+
static_assert(N == 1);
14+
canary1<N>();
15+
}
16+
void f() requires(N == 2) {
17+
static_assert(N == 2);
18+
canary2<N>();
19+
}
20+
};
21+
22+
// This checks that `canary1<1>` and `canaray2<2>` are instantiated, thus
23+
// indirectly validating that the correct candidates of `A::f` were really
24+
// instantiated each time.
25+
// The `static_assert`s validate we don't instantiate wrong candidates.
26+
27+
// CHECK:{{.*}}FunctionTemplateDecl {{.*}} canary1
28+
// CHECK: {{.*}}TemplateArgument integral
29+
// CHECK-SAME: {{1$}}
30+
template struct A<1>;
31+
32+
// CHECK: {{.*}}FunctionTemplateDecl {{.*}} canary2
33+
// CHECK: {{.*}}TemplateArgument integral
34+
// CHECK-SAME: {{2$}}
35+
template struct A<2>;
36+
37+
template struct A<3>;
38+
}

0 commit comments

Comments
 (0)