This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Handle LambdaExprs

Authored by tbaeder on Mar 14 2023, 3:46 AM.



Unfortunately I couldn't find an existing test file in test/SemaCXX that focused on lambdas in constant expressions.

Diff Detail

Event Timeline

tbaeder created this revision.Mar 14 2023, 3:46 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 14 2023, 3:46 AM
tbaeder requested review of this revision.Mar 14 2023, 3:46 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 14 2023, 3:46 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
aaron.ballman added inline comments.May 5 2023, 11:35 AM

UB alert -- _L is reserved; let's pick names without leading underscores or shadowing.


Can you add comments explaining what the unsigned, bool pair is encoding?


Why is this a pointer? Since it's not really implemented, I'd recommend removing this for now and adding it back when you add support for capturing this.


How about some tests like:

constexpr int call_thru_func_ptr(int i) {
  auto l = [](int i) { return i; };
  int (*fp)(int) = l;
  return fp(i);  
static_assert(call_thru_func_ptr(12) == 12);

constexpr int call_through_copied_lambda(auto lam, int i) {
  auto copy = lam;
  return copy(i);

constexpr int call_through_copied_lambda(auto lam) {
  auto copy = lam;
  return copy();

void func() {
  constexpr int i = 12;
  static_assert(call_through_copied_lambda([i]() { return i; }) == 12);
tbaeder added inline comments.May 7 2023, 1:03 AM


array.cpp:1245:15: error: static assertion expression is not an integral constant expression
 1245 | static_assert(call_thru_func_ptr(12) == 12);
      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
array.cpp:1243:10: note: non-constexpr function '__invoke' cannot be used in a constant expression
 1243 |   return fp(i);
      |          ^
array.cpp:1245:15: note: in call to 'call_thru_func_ptr(12)'
 1245 | static_assert(call_thru_func_ptr(12) == 12);
      |               ^
array.cpp:1239:12: note: declared here
 1239 |   auto l = [](int i) { return i; };
      |            ^
tbaeder updated this revision to Diff 520155.May 7 2023, 1:14 AM
tbaeder marked 3 inline comments as done.
tbaeder added inline comments.May 7 2023, 10:37 PM

Ah, I didn't know there is something like a "lambda static invoker". I see the current interpreter basically checks for that and then calls the lambda call operator instead. Doing that is hard for me though, because the call operator requires different arguments and I can't just itnogre the static invoker either because it has an empty body.

tbaeder added inline comments.May 8 2023, 1:57 AM

Okay, I think I figured it out, I'm just special-casing the static invoker and emitting byte code for its body manually. This will make the patch larger though.

aaron.ballman added inline comments.May 8 2023, 4:33 AM

Hmmm, aren't you going to need to emit a body for the static invoker for calling through a function pointer to it (the call_thru_func_ptr example)? I would imagine you'd need to emit both the static invoker and the call operator and have the static invoker call the call operator.

shafik added inline comments.May 8 2023, 2:14 PM

Fun case

int constexpr f() {
    return [x = 10] {
       decltype(x) y; // type int b/c not odr use
                      // refers to original init-capture
       auto &z = x; // type const int & b/c odr use
                     // refers to lambdas copy of x
        y = 10; // Ok
        //z = 10; // Ill-formed
        return y;

constexpr int x = f();
tbaeder updated this revision to Diff 522204.May 15 2023, 8:21 AM
tbaeder marked an inline comment as done.
aaron.ballman accepted this revision.May 16 2023, 7:39 AM


This revision is now accepted and ready to land.May 16 2023, 7:39 AM
This revision was automatically updated to reflect the committed changes.