Skip to content

Commit

Permalink
[clang] Skip re-building lambda expressions in parameters to consteva…
Browse files Browse the repository at this point in the history
…l fns.

As discussed in this [comment](llvm#56183 (comment)),
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: llvm#56183
Fixes: llvm#51695
Fixes: llvm#50455
Fixes: llvm#54872
Fixes: llvm#54587

Differential Revision: https://reviews.llvm.org/D132945

(cherry picked from commit e7eec38)
  • Loading branch information
usx95 committed Sep 6, 2022
1 parent 4ba6a9c commit 2201b17
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
6 changes: 6 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,12 @@ C++20 Feature Support
- As per "Conditionally Trivial Special Member Functions" (P0848), it is
now possible to overload destructors using concepts. Note that the rest
of the paper about other special member functions is not yet implemented.
- 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
^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17600,6 +17600,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() {
Expand Down
69 changes: 69 additions & 0 deletions clang/test/SemaCXX/cxx2a-consteval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,3 +766,72 @@ void test() {
static_assert(c == 8);
}
}

// 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

0 comments on commit 2201b17

Please sign in to comment.