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