tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

  Move the logic for initialization of a lambda into
  visitRecordInitializer(). When we visit a LambdaExpr outside of the
  visitInitializer() logic, we need to create a new local variable so we
  have a place to write the lambda members into.

This fixes passing lambas as arguments to function calls.

In that case, we visit a `LambdaExpr` without it being an initializer to 
anything, so we should create a new local variable and return a pointer to it, 
which we then pass to the function call.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D153616

Files:
  clang/lib/AST/Interp/ByteCodeExprGen.cpp
  clang/test/AST/Interp/lambda.cpp

Index: clang/test/AST/Interp/lambda.cpp
===================================================================
--- clang/test/AST/Interp/lambda.cpp
+++ clang/test/AST/Interp/lambda.cpp
@@ -107,6 +107,29 @@
   static_assert(foo() == 1); // expected-error {{not an integral constant expression}}
 }
 
+namespace LambdasAsParams {
+  template<typename F>
+  constexpr auto call(F f) {
+    return f();
+  }
+  static_assert(call([](){ return 1;}) == 1);
+  static_assert(call([](){ return 2;}) == 2);
+
+
+  constexpr unsigned L = call([](){ return 12;});
+  static_assert(L == 12);
+
+
+  constexpr float heh() {
+    auto a = []() {
+      return 1.0;
+    };
+
+    return static_cast<float>(a());
+  }
+  static_assert(heh() == 1.0);
+}
+
 namespace StaticInvoker {
   constexpr int sv1(int i) {
     auto l = []() { return 12; };
Index: clang/lib/AST/Interp/ByteCodeExprGen.cpp
===================================================================
--- clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1062,39 +1062,15 @@
 
 template <class Emitter>
 bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
-  // XXX We assume here that a pointer-to-initialize is on the stack.
 
-  const Record *R = P.getOrCreateRecord(E->getLambdaClass());
-
-  auto *CaptureInitIt = E->capture_init_begin();
-  // Initialize all fields (which represent lambda captures) of the
-  // record with their initializers.
-  for (const Record::Field &F : R->fields()) {
-    const Expr *Init = *CaptureInitIt;
-    ++CaptureInitIt;
-
-    if (std::optional<PrimType> T = classify(Init)) {
-      if (!this->visit(Init))
-        return false;
-
-      if (!this->emitSetField(*T, F.Offset, E))
-        return false;
-    } else {
-      if (!this->emitDupPtr(E))
-        return false;
-
-      if (!this->emitGetPtrField(F.Offset, E))
-        return false;
-
-      if (!this->visitInitializer(Init))
-        return false;
+  if (std::optional<unsigned> GI = allocateLocal(E, /*IsExtended=*/false)) {
+    if (!this->emitGetPtrLocal(*GI, E))
+      return false;
 
-      if (!this->emitPopPtr(E))
-        return false;
-    }
+    return this->visitRecordInitializer(E);
   }
 
-  return true;
+  return false;
 }
 
 template <class Emitter>
@@ -1714,7 +1690,39 @@
     return this->visitConditional(
         ACO, [this](const Expr *E) { return this->visitRecordInitializer(E); });
   } else if (const auto *LE = dyn_cast<LambdaExpr>(Initializer)) {
-    return this->VisitLambdaExpr(LE);
+    // XXX We assume here that a pointer-to-initialize is on the stack.
+
+    const Record *R = P.getOrCreateRecord(LE->getLambdaClass());
+
+    auto *CaptureInitIt = LE->capture_init_begin();
+    // Initialize all fields (which represent lambda captures) of the
+    // record with their initializers.
+    for (const Record::Field &F : R->fields()) {
+      const Expr *Init = *CaptureInitIt;
+      ++CaptureInitIt;
+
+      if (std::optional<PrimType> T = classify(Init)) {
+        if (!this->visit(Init))
+          return false;
+
+        if (!this->emitSetField(*T, F.Offset, LE))
+          return false;
+      } else {
+        if (!this->emitDupPtr(LE))
+          return false;
+
+        if (!this->emitGetPtrField(F.Offset, LE))
+          return false;
+
+        if (!this->visitInitializer(Init))
+          return false;
+
+        if (!this->emitPopPtr(LE))
+          return false;
+      }
+    }
+
+    return true;
   }
 
   return false;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to