| // 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}} |
| |
| template <class T, auto U> |
| concept same_as_v = __is_same(T, decltype(U)); // #same_as_v |
| |
| template <auto... Vs> constexpr auto baz() { |
| return Overloaded{[](same_as_v<Vs> auto value) { return value; }...}; // #baz |
| } |
| |
| static_assert(baz<1, 1.>()(123) == 123); |
| static_assert(baz<1, 1.>()(2.718) == 2.718); |
| |
| static_assert(baz<1, 1.>()('c')); |
| // expected-error@-1 {{no matching function}} |
| |
| // expected-note@#baz {{constraints not satisfied}} |
| // expected-note@#baz {{'same_as_v<char, 1>' evaluated to false}} |
| // expected-note@#same_as_v {{evaluated to false}} |
| |
| // expected-note@#baz {{constraints not satisfied}} |
| // expected-note@#baz {{'same_as_v<char, 1.>' evaluated to false}} |
| // expected-note@#same_as_v {{evaluated to false}} |
| |
| template <auto... Ts> constexpr auto bazz() { |
| return Overloaded{[](same_as_v<Ts> auto value) { return Ts; }...}; // #bazz |
| } |
| |
| static_assert(bazz<1, 2>()(1)); |
| // expected-error@-1 {{is ambiguous}} |
| // expected-note@#bazz 2{{candidate function [with value:auto = int]}} |
| |
| template <class T> concept C2 = sizeof(T) >= sizeof(int); |
| template <class... Ts> static constexpr auto trailing() { |
| return Overloaded{[](auto) requires (C2<Ts> && C2<int>) { return 0; }...}; // #trailing |
| } |
| static_assert(trailing<int, long>()(0)); |
| // expected-error@-1 {{is ambiguous}} |
| // expected-note@#trailing 2{{candidate function [with auto:1 = int]}} |
| |
| |
| } // namespace GH101754 |
| |
| namespace GH131798 { |
| template <class T0> |
| struct tuple { T0 elem0; }; |
| |
| template <class, class> |
| concept C = true; |
| |
| template <int> |
| struct Foo {}; |
| |
| template <int... Vals> |
| constexpr tuple fs{[] (C<Foo<Vals>> auto) {}...}; |
| |
| int main() { |
| fs<0>.elem0(1); |
| } |
| } // namspace GH131798 |