================
@@ -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@-1 {{no viable constructor}} \
+//   expected-note@-6 {{constraints not satisfied}} \
+//   expected-note@-5 {{because substituted constraint expression is 
ill-formed}} \
+//   expected-note@-6 {{implicit deduction guide declared as 'template 
<typename T, typename ...Ts> B(T val, Ts ...tail) -> B<T> requires 
(True<tail...>())'}} \
+//   expected-note@-8 {{function template not viable}} \
+//   expected-note@-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:

Though been discussed in https://github.com/llvm/llvm-project/issues/98592, 
It's not so clear to me as to whether this case should be accepted:

While the wording from 
[[over.match.class.deduct]p1.1.2](https://eel.is/c++draft/over.match.class.deduct#1.1.2)
 suggests the constraint of the synthesized CTAD is the *conjunction* of that 
of C and that of the constructor, the note there also seems to imply the 
constraint from C should be checked before the checking of the constraint of 
constructor, so this example should not compile that way. (The overload 
resolution would pick up the explicit CTAD guide if C's required-clause were 
not propagated into the implicit CTAD guide.)

I still build up a && operator for the literal "conjunction" currently, but I 
think I can remove that if our reading is wrong.

https://github.com/llvm/llvm-project/pull/111143
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to