| // RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s |
| // RUN: %clang_cc1 -fsyntax-only -verify %s |
| // RUN: %clang_cc1 -std=c++23 -fms-extensions -fsyntax-only -verify %s |
| // RUN: %clang_cc1 -fcuda-is-device -fms-extensions -fsyntax-only -verify %s |
| // RUN: %clang_cc1 -std=c++23 -fcuda-is-device -fms-extensions -fsyntax-only -verify %s |
| // expected-no-diagnostics |
| |
| // A '[' can begin a Microsoft attribute list under -fms-extensions, but it can |
| // also begin a C++ lambda-introducer. A lambda passed to a constructor via CTAD |
| // must not have its capture list consumed as a (possibly empty) Microsoft |
| // attribute, which previously misparsed the initializer as a function |
| // declarator under -fms-extensions. |
| // |
| // A lambda and a Microsoft attribute are told apart by what follows the |
| // (possibly attributed) '[...]' introducer. A lambda continues with a parameter |
| // list, body, template parameter list, or lambda declarator ending in an |
| // unambiguous continuation. A Microsoft attribute is followed by the |
| // declaration it appertains to. |
| |
| #include "Inputs/cuda.h" |
| |
| template <typename F> struct Wrapper { |
| F f; |
| __host__ Wrapper(F fn) : f(fn) {} |
| }; |
| template <typename F> Wrapper(F) -> Wrapper<F>; |
| |
| void empty_and_defaults() { |
| Wrapper a([] __device__ () {}); |
| Wrapper b([=] __device__ () {}); |
| Wrapper c([&] __device__ () {}); |
| Wrapper d([] __device__ {}); |
| (void)a; (void)b; (void)c; (void)d; |
| } |
| |
| void interleaved_noinline() { |
| Wrapper a([] __device__ __noinline__ () {}); |
| Wrapper b([] __attribute__((device)) __noinline__ |
| __attribute__((host)) () {}); |
| Wrapper c([] __device__ __noinline__ {}); |
| (void)a; (void)b; (void)c; |
| } |
| |
| #if __cplusplus >= 202302L |
| void omitted_parameter_list() { |
| Wrapper a([] __device__ noexcept {}); |
| Wrapper b([] __device__ -> int { return 1; }); |
| Wrapper c([] __device__ mutable {}); |
| Wrapper d([] __device__ constexpr {}); |
| Wrapper e([] __device__ consteval {}); |
| Wrapper f([] __device__ static {}); |
| Wrapper g([] __device__ mutable constexpr noexcept -> int { return 1; }); |
| Wrapper h([] __device__ mutable [[]] {}); |
| Wrapper i([] __device__ __noinline__ mutable constexpr noexcept -> int { |
| return 1; |
| }); |
| (void)a; (void)b; (void)c; (void)d; |
| (void)e; (void)f; (void)g; (void)h; (void)i; |
| } |
| |
| void explicit_template_parameter_list() { |
| Wrapper a([] __device__ <typename T>(T x) { return x; }); |
| (void)a; |
| } |
| #endif |
| |
| void named_captures() { |
| int values[] = {1}; |
| int x = 0; |
| Wrapper a([x] __device__ () { return x; }); |
| Wrapper b([&x] __device__ () { x++; }); |
| Wrapper c([y = x] __device__ () { return y; }); |
| Wrapper d([x, &x2 = x] __device__ () { return x + x2; }); |
| Wrapper e([a = values[0], b = [] { return 2; }()] __device__ () { |
| return a + b; |
| }); |
| (void)a; (void)b; (void)c; (void)d; (void)e; |
| } |
| |
| struct S { |
| int m = 0; |
| void g() { |
| Wrapper a([this] __device__ () { return m; }); |
| Wrapper b([*this] __device__ () { return m; }); |
| (void)a; (void)b; |
| } |
| }; |