[clang] [Clang] Implement CWG 2628 "Implicit deduction guides should propagate constraints" (PR #111143)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 7 06:52:30 PDT 2024
================
@@ -478,3 +478,166 @@ A a{.f1 = {1}};
// CHECK-NEXT: `-DeclRefExpr {{.+}} <col:10> 'int' NonTypeTemplateParm {{.+}} 'N' 'int'
} // namespace GH83368
+
+namespace GH60777 {
+
+template <typename... Ts> constexpr bool True() { return true; }
+
+template <typename T>
+ requires(sizeof(T) == 4)
+struct A {
+ template <typename... Ts>
+ requires(sizeof...(Ts) == 0)
+ A(T val, Ts... tail)
+ requires(True<Ts...>())
+ {}
+};
+
+A a(42);
+
+// `requires (sizeof(T) == 4)` goes into the deduction guide together with
+// `requires (True<Ts...>())`, while `requires(sizeof...(Ts) == 0)` goes into
+// the template parameter list of the synthesized declaration.
+
+// CHECK-LABEL: Dumping GH60777::<deduction guide for A>:
+// CHECK-NEXT: FunctionTemplateDecl 0x{{.+}} <{{.+}}> {{.+}} implicit <deduction guide for A>
+// CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <{{.+}}> col:20 referenced typename depth 0 index 0 T
+// CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <{{.+}}> col:25 typename depth 0 index 1 ... Ts
+// CHECK-NEXT: |-ParenExpr 0x{{.+}} <{{.+}}> 'bool'
+// CHECK-NEXT: | `-BinaryOperator 0x{{.+}} <{{.+}}> 'bool' '=='
+// CHECK-NEXT: | |-SizeOfPackExpr 0x{{.+}} <{{.+}}> 'unsigned long' 0x{{.+}} Ts
+// CHECK-NEXT: | | `-TemplateArgument type 'Ts...':'type-parameter-0-1...'
+// CHECK-NEXT: | | `-PackExpansionType 0x{{.+}} 'Ts...' dependent
+// CHECK-NEXT: | | `-TemplateTypeParmType 0x{{.+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: | | `-TemplateTypeParm 0x{{.+}} 'Ts'
+// CHECK-NEXT: | `-ImplicitCastExpr 0x{{.+}} <{{.+}}> 'unsigned long' <IntegralCast>
+// CHECK-NEXT: | `-IntegerLiteral 0x{{.+}} <{{.+}}> 'int' 0
+// CHECK-NEXT: |-CXXDeductionGuideDecl 0x{{.+}} <{{.+}}> line:{{.+}} implicit <deduction guide for A> 'auto (T, Ts...) -> A<T>'
+// CHECK-NEXT: | |-ParmVarDecl 0x{{.+}} <{{.+}}> col:{{.+}} val 'T'
+// CHECK-NEXT: | |-ParmVarDecl 0x{{.+}} <{{.+}}> col:{{.+}} tail 'Ts...' pack
+// CHECK-NEXT: | `-BinaryOperator 0x{{.+}} <{{.+}}> 'bool' '&&'
+// CHECK-NEXT: | |-ParenExpr 0x{{.+}} <{{.+}}> 'bool'
+// CHECK-NEXT: | | `-BinaryOperator 0x{{.+}} <{{.+}}> 'bool' '=='
+// CHECK-NEXT: | | |-UnaryExprOrTypeTraitExpr 0x{{.+}} <{{.+}}> 'unsigned long' sizeof 'T'
+// CHECK-NEXT: | | `-ImplicitCastExpr 0x{{.+}} <{{.+}}> 'unsigned long' <IntegralCast>
+// CHECK-NEXT: | | `-IntegerLiteral 0x{{.+}} <{{.+}}> 'int' 4
+// CHECK-NEXT: | `-ParenExpr 0x{{.+}} <{{.+}}> '<dependent type>'
+// CHECK-NEXT: | `-CallExpr 0x{{.+}} <{{.+}}> '<dependent type>'
+// CHECK-NEXT: | `-UnresolvedLookupExpr 0x{{.+}} <col:14, col:24> '<dependent type>' lvalue (ADL) = 'True' 0x{{.+}}
+// CHECK-NEXT: | `-TemplateArgument type 'Ts...':'type-parameter-0-1...'
+// CHECK-NEXT: | `-PackExpansionType 0x{{.+}} 'Ts...' dependent
+// CHECK-NEXT: | `-TemplateTypeParmType 0x{{.+}} 'Ts' dependent contains_unexpanded_pack depth 0 index 1 pack
+// CHECK-NEXT: | `-TemplateTypeParm 0x{{.+}} 'Ts'
+
+template <typename T>
+struct B {
+ template <typename... Ts>
+ B(T val, Ts... tail)
+ requires(True<tail...>())
+ {}
+};
+
+B b(42, 43);
+// expected-error at -1 {{no viable constructor}} \
+// expected-note at -6 {{constraints not satisfied}} \
+// expected-note at -5 {{because substituted constraint expression is ill-formed}} \
+// expected-note at -6 {{implicit deduction guide declared as 'template <typename T, typename ...Ts> B(T val, Ts ...tail) -> B<T> requires (True<tail...>())'}} \
+// expected-note at -8 {{function template not viable}} \
+// expected-note at -8 {{implicit deduction guide declared as 'template <typename T> B(B<T>) -> B<T>'}}
+
+} // namespace GH60777
+
+// Examples from @hokein.
+namespace GH98592 {
+
+template <class T> concept True = true;
+double arr3[3];
+
+template <class T>
+struct X {
+ const int size;
+ template <class U>
+ constexpr X(T, U(&)[3]) requires True<T> : size(sizeof(T)) {}
+};
+
+template <typename T, typename U>
+X(T, U (&)[3]) -> X<U>;
+
+constexpr X x(3, arr3);
+
+// The synthesized deduction guide is more constrained than the explicit one.
+static_assert(x.size == 4);
+
+// CHECK-LABEL: Dumping GH98592::<deduction guide for X>:
+// CHECK-NEXT: FunctionTemplateDecl 0x{{.+}} <{{.+}}> col:13 implicit <deduction guide for X>
+// CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <{{.+}}> col:17 referenced class depth 0 index 0 T
+// CHECK-NEXT: |-TemplateTypeParmDecl 0x{{.+}} <{{.+}}> col:19 class depth 0 index 1 U
+// CHECK-NEXT: |-CXXDeductionGuideDecl 0x{{.+}} <{{.+}}> col:13 implicit <deduction guide for X> 'auto (T, U (&)[3]) -> X<T>'
+// CHECK-NEXT: | |-ParmVarDecl 0x{{.+}} <col:15> col:16 'T'
+// CHECK-NEXT: | |-ParmVarDecl 0x{{.+}} <col:18, col:24> col:21 'U (&)[3]'
+// CHECK-NEXT: | `-ConceptSpecializationExpr 0x{{.+}} <col:36, col:42> 'bool' Concept 0x{{.+}} 'True'
+// CHECK-NEXT: | |-ImplicitConceptSpecializationDecl 0x{{.+}} <{{.+}}> col:28
+// CHECK-NEXT: | | `-TemplateArgument type 'type-parameter-0-0'
+// CHECK-NEXT: | | `-TemplateTypeParmType 0x{{.+}} 'type-parameter-0-0' dependent depth 0 index 0
+// CHECK-NEXT: | `-TemplateArgument <{{.+}}> type 'T':'type-parameter-0-0'
+// CHECK-NEXT: | `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
+// CHECK-NEXT: | `-TemplateTypeParm 0x{{.+}} 'T'
+// CHECK-NEXT: `-CXXDeductionGuideDecl 0x{{.+}} <col:3, col:63> col:13 implicit used <deduction guide for X> 'auto (int, double (&)[3]) -> GH98592::X<int>' implicit_instantiation
+// CHECK-NEXT: |-TemplateArgument type 'int'
+// CHECK-NEXT: | `-BuiltinType 0x{{.+}} 'int'
+// CHECK-NEXT: |-TemplateArgument type 'double'
+// CHECK-NEXT: | `-BuiltinType 0x{{.+}} 'double'
+// CHECK-NEXT: |-ParmVarDecl 0x{{.+}} <col:15> col:16 'int'
+// CHECK-NEXT: |-ParmVarDecl 0x{{.+}} <col:18, col:24> col:21 'double (&)[3]'
+// CHECK-NEXT: `-ConceptSpecializationExpr 0x{{.+}} <col:36, col:42> 'bool' Concept 0x{{.+}} 'True'
+// CHECK-NEXT: |-ImplicitConceptSpecializationDecl 0x{{.+}} <{{.+}}> col:28
+// CHECK-NEXT: | `-TemplateArgument type 'type-parameter-0-0'
+// CHECK-NEXT: | `-TemplateTypeParmType 0x{{.+}} 'type-parameter-0-0' dependent depth 0 index 0
+// CHECK-NEXT: `-TemplateArgument <{{.+}}> type 'T':'type-parameter-0-0'
+// CHECK-NEXT: `-TemplateTypeParmType 0x{{.+}} 'T' dependent depth 0 index 0
+// CHECK-NEXT: `-TemplateTypeParm 0x{{.+}} 'T'
+
+template <class T> requires True<T> struct Y {
+ const int size;
+ template <class U>
+ constexpr Y(T, U(&)[3]) : size(sizeof(T)) {}
+};
+
+template <typename T, typename U> Y(T, U (&)[3]) -> Y<U>;
+
+constexpr Y y(3, arr3);
+
+// Likewise, the synthesized deduction guide should be preferred
+// according to [over.match.class.deduct]p1.
+static_assert(y.size == 4);
----------------
zyn0217 wrote:
(Also tagging @zygoloid who added that note https://cplusplus.github.io/CWG/issues/2714.html)
https://github.com/llvm/llvm-project/pull/111143
More information about the cfe-commits
mailing list