diff options
author | Utkarsh Saxena <usx@google.com> | 2022-08-30 16:57:07 +0200 |
---|---|---|
committer | Utkarsh Saxena <usx@google.com> | 2022-09-02 12:30:52 +0200 |
commit | e7eec38246560781e0a4020b19c7eb038a8c5655 (patch) | |
tree | 6e9308e0405b903277744e45b5144569560c7239 /clang | |
parent | 51d4c7ceea61b5d83ba52398b5ca6d58d7551044 (diff) | |
download | llvm-e7eec38246560781e0a4020b19c7eb038a8c5655.zip llvm-e7eec38246560781e0a4020b19c7eb038a8c5655.tar.gz llvm-e7eec38246560781e0a4020b19c7eb038a8c5655.tar.bz2 |
[clang] Skip re-building lambda expressions in parameters to consteval fns.
As discussed in this [comment](https://github.com/llvm/llvm-project/issues/56183#issuecomment-1224331699),
we end up building the lambda twice: once while parsing the function calls and then again while handling the immediate invocation.
This happens specially during removing nested immediate invocation.
Eg: When we have another consteval function as the parameter along with this lambda expression. Eg: `foo(bar([]{}))`, `foo(bar(), []{})`
While removing such nested immediate invocations, we should not rebuild this lambda. (IIUC, rebuilding a lambda would always generate a new type which will never match the original type from parsing)
Fixes: https://github.com/llvm/llvm-project/issues/56183
Fixes: https://github.com/llvm/llvm-project/issues/51695
Fixes: https://github.com/llvm/llvm-project/issues/50455
Fixes: https://github.com/llvm/llvm-project/issues/54872
Fixes: https://github.com/llvm/llvm-project/issues/54587
Differential Revision: https://reviews.llvm.org/D132945
Diffstat (limited to 'clang')
-rw-r--r-- | clang/docs/ReleaseNotes.rst | 7 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 5 | ||||
-rw-r--r-- | clang/test/SemaCXX/cxx2a-consteval.cpp | 79 |
3 files changed, 91 insertions, 0 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 41fb9e4..2a92f65 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -211,9 +211,16 @@ C++20 Feature Support - Correctly set expression evaluation context as 'immediate function context' in consteval functions. This fixes `GH51182 <https://github.com/llvm/llvm-project/issues/51182>` + - Fixes an assert crash caused by looking up missing vtable information on ``consteval`` virtual functions. Fixes `GH55065 <https://github.com/llvm/llvm-project/issues/55065>`_. +- Skip rebuilding lambda expressions in arguments of immediate invocations. + This fixes `GH56183 <https://github.com/llvm/llvm-project/issues/56183>`_, + `GH51695 <https://github.com/llvm/llvm-project/issues/51695>`_, + `GH50455 <https://github.com/llvm/llvm-project/issues/50455>`_, + `GH54872 <https://github.com/llvm/llvm-project/issues/54872>`_, + `GH54587 <https://github.com/llvm/llvm-project/issues/54587>`_. C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 80ac673..f124ad3 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -17598,6 +17598,11 @@ static void RemoveNestedImmediateInvocation( DRSet.erase(E); return E; } + ExprResult TransformLambdaExpr(LambdaExpr *E) { + // Do not rebuild lambdas to avoid creating a new type. + // Lambdas have already been processed inside their eval context. + return E; + } bool AlwaysRebuild() { return false; } bool ReplacingOriginal() { return true; } bool AllowSkippingCXXConstructExpr() { diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp index 09129a2..1a80977 100644 --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -939,3 +939,82 @@ consteval T mid(const T& a, const T& b, const T& c) { static_assert(max(1,2)==2); static_assert(mid(1,2,3)==2); } // namespace GH51182 + +// https://github.com/llvm/llvm-project/issues/56183 +namespace GH56183 { +consteval auto Foo(auto c) { return c; } +consteval auto Bar(auto f) { return f(); } +void test() { + constexpr auto x = Foo(Bar([] { return 'a'; })); + static_assert(x == 'a'); +} +} // namespace GH56183 + +// https://github.com/llvm/llvm-project/issues/51695 +namespace GH51695 { +// Original ======================================== +template <typename T> +struct type_t {}; + +template <typename...> +struct list_t {}; + +template <typename T, typename... Ts> +consteval auto pop_front(list_t<T, Ts...>) -> auto { + return list_t<Ts...>{}; +} + +template <typename... Ts, typename F> +consteval auto apply(list_t<Ts...>, F fn) -> auto { + return fn(type_t<Ts>{}...); +} + +void test1() { + constexpr auto x = apply(pop_front(list_t<char, char>{}), + []<typename... Us>(type_t<Us>...) { return 42; }); + static_assert(x == 42); +} +// Reduced 1 ======================================== +consteval bool zero() { return false; } + +template <typename F> +consteval bool foo(bool, F f) { + return f(); +} + +void test2() { + constexpr auto x = foo(zero(), []() { return true; }); + static_assert(x); +} + +// Reduced 2 ======================================== +template <typename F> +consteval auto bar(F f) { return f;} + +void test3() { + constexpr auto t1 = bar(bar(bar(bar([]() { return true; }))))(); + static_assert(t1); + + int a = 1; // expected-note {{declared here}} + auto t2 = bar(bar(bar(bar([=]() { return a; }))))(); // expected-error-re {{call to consteval function 'GH51695::bar<(lambda at {{.*}})>' is not a constant expression}} + // expected-note@-1 {{read of non-const variable 'a' is not allowed in a constant expression}} + + constexpr auto t3 = bar(bar([x=bar(42)]() { return x; }))(); + static_assert(t3==42); + constexpr auto t4 = bar(bar([x=bar(42)]() consteval { return x; }))(); + static_assert(t4==42); +} + +} // namespace GH51695 + +// https://github.com/llvm/llvm-project/issues/50455 +namespace GH50455 { +void f() { + []() consteval { int i{}; }(); + []() consteval { int i{}; ++i; }(); +} +void g() { + (void)[](int i) consteval { return i; }(0); + (void)[](int i) consteval { return i; }(0); +} +} // namespace GH50455 |