1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
|
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
namespace GH85667 {
template <class T>
struct identity {
using type = T;
};
template <class> using ElementType = int;
template <class = void> void f() {
static_assert([]<class... Is>(Is... x) {
return ([I(x)] {
return I;
}() + ...);
}(1, 2) == 3);
[]<class... Is>(Is... x) {
return ([](auto y = Is()) { return y + 1; }() + ...); // expected-error {{no matching function}} \
// expected-note {{couldn't infer template argument 'y:auto'}} \
// expected-note@-1 {{requested here}}
// expected-note@#instantiate-f {{requested here}}
}(1);
[]<class... Is>() {
([]<class = Is>(Is)
noexcept(bool(Is()))
{}(Is()),
...);
}.template operator()<char, int, float>();
static_assert(__is_same(decltype([]<class... Is>() {
return ([]() -> decltype(Is()) { return {}; }(),
...);
}.template operator()<int, char>()),
char));
[]<class... Is>() {
return ([]<class... Ts>() -> decltype(Is()) { return Ts(); }() + ...);
// expected-error@-1 {{unexpanded parameter pack 'Ts'}}
}.template operator()<int, int>();
// https://github.com/llvm/llvm-project/issues/56852
[]<class... Is>(Is...) {
([] {
using T = identity<Is>::type;
}(), ...);
}(1, 2);
[]<class... Is>(Is...) {
([] { using T = ElementType<Is>; }(), ...);
}(1);
[](auto ...y) {
([y] { }(), ...);
}();
[](auto ...x) {
([&](auto ...y) {
([x..., y] { }(), ...);
})(1);
}(2, 'b');
#if 0
// FIXME: https://github.com/llvm/llvm-project/issues/18873
[](auto ...x) { // #1
([&](auto ...y) { // #2
([x, y] { }(), ...); // #3
})(1, 'a'); // #4
}(2, 'b'); // #5
// We run into another crash for the above lambda because of the absence of a
// mechanism that rebuilds an unexpanded pack from an expanded Decls.
//
// Basically, this happens after `x` at #1 being expanded when the template
// arguments at #5, deduced as <int, char>, are ready. When we want to
// instantiate the body of #1, we first instantiate the CallExpr at #4, which
// boils down to the lambda's instantiation at #2. To that end, we have to
// instantiate the body of it, which turns out to be #3. #3 is a CXXFoldExpr,
// and we immediately have to hold off on the expansion because we don't have
// corresponding template arguments (arguments at #4 are not transformed yet) for it.
// Therefore, we want to rebuild a CXXFoldExpr, which requires another pattern
// transformation of the lambda inside #3. Then we need to find an unexpanded form
// of such a Decl of x at the time of transforming the capture, which is impossible
// because the instantiated form has been expanded at #1!
[](auto ...x) { // #outer
([&](auto ...y) { // #inner
([x, y] { }(), ...);
// expected-error@-1 {{parameter pack 'y' that has a different length (4 vs. 3) from outer parameter packs}}
// expected-note-re@#inner {{function template specialization {{.*}} requested here}}
// expected-note-re@#outer {{function template specialization {{.*}} requested here}}
// expected-note-re@#instantiate-f {{function template specialization {{.*}} requested here}}
})('a', 'b', 'c');
}(0, 1, 2, 3);
#endif
}
template void f(); // #instantiate-f
} // namespace GH85667
namespace GH99877 {
struct tuple {
int x[3];
};
template <class F> int apply(F f, tuple v) { return f(v.x[0], v.x[1], v.x[2]); }
int Cartesian1(auto x, auto y) {
return apply(
[&](auto... xs) {
return (apply([xs](auto... ys) { return (ys + ...); }, y) + ...);
},
x);
}
int Cartesian2(auto x, auto y) {
return apply(
[&](auto... xs) {
return (apply([zs = xs](auto... ys) { return (ys + ...); }, y) + ...);
},
x);
}
template <int...> struct Ints {};
template <int> struct Choose {
template <class> struct Templ;
};
template <int... x> int Cartesian3(auto y) {
return [&]<int... xs>(Ints<xs...>) {
// check in default template arguments for
// - type template parameters,
(void)(apply([]<class = decltype(xs)>(auto... ys) { return (ys + ...); },
y) +
...);
// - template template parameters.
(void)(apply([]<template <class> class = Choose<xs>::template Templ>(
auto... ys) { return (ys + ...); },
y) +
...);
// - non-type template parameters,
return (apply([]<int = xs>(auto... ys) { return (ys + ...); }, y) + ...);
}(Ints<x...>());
}
template <int... x> int Cartesian4(auto y) {
return [&]<int... xs>(Ints<xs...>) {
return (
apply([]<decltype(xs) xx = 1>(auto... ys) { return (ys + ...); }, y) +
...);
}(Ints<x...>());
}
// FIXME: Attributes should preserve the ContainsUnexpandedPack flag.
#if 0
int Cartesian5(auto x, auto y) {
return apply(
[&](auto... xs) {
return (apply([](auto... ys) __attribute__((
diagnose_if(!__is_same(decltype(xs), int), "message",
"error"))) { return (ys + ...); },
y) +
...);
},
x);
}
#endif
void foo() {
auto x = tuple({1, 2, 3});
auto y = tuple({4, 5, 6});
Cartesian1(x, y);
Cartesian2(x, y);
Cartesian3<1, 2, 3>(y);
Cartesian4<1, 2, 3>(y);
#if 0
Cartesian5(x, y);
#endif
}
} // namespace GH99877
namespace GH101754 {
template <typename... Ts> struct Overloaded : Ts... {
using Ts::operator()...;
};
template <typename... Ts> Overloaded(Ts...) -> Overloaded<Ts...>;
template <class T, class U>
concept same_as = __is_same(T, U); // #same_as
template <typename... Ts> constexpr auto foo() {
return Overloaded{[](same_as<Ts> auto value) { return value; }...}; // #lambda
}
static_assert(foo<int, double>()(123) == 123);
static_assert(foo<int, double>()(2.718) == 2.718);
static_assert(foo<int, double>()('c'));
// expected-error@-1 {{no matching function}}
// expected-note@#lambda {{constraints not satisfied}}
// expected-note@#lambda {{'same_as<char, int>' evaluated to false}}
// expected-note@#same_as {{evaluated to false}}
// expected-note@#lambda {{constraints not satisfied}}
// expected-note@#lambda {{'same_as<char, double>' evaluated to false}}
// expected-note@#same_as {{evaluated to false}}
template <class T, class U, class V>
concept C = same_as<T, U> && same_as<U, V>; // #C
template <typename... Ts> constexpr auto bar() {
return ([]<class Up>() {
return Overloaded{[](C<Up, Ts> auto value) { // #bar
return value;
}...};
}.template operator()<Ts>(), ...);
}
static_assert(bar<int, float>()(3.14f)); // OK, bar() returns the last overload i.e. <float>.
static_assert(bar<int, float>()(123));
// expected-error@-1 {{no matching function}}
// expected-note@#bar {{constraints not satisfied}}
// expected-note@#bar {{'C<int, float, int>' evaluated to false}}
// expected-note@#C {{evaluated to false}}
// expected-note@#bar {{constraints not satisfied}}
// expected-note@#bar {{'C<int, float, float>' evaluated to false}}
// expected-note@#C {{evaluated to false}}
// expected-note@#same_as 2{{evaluated to false}}
} // namespace GH101754
|