Author: Timm Baeder Date: 2026-01-12T12:34:22+01:00 New Revision: f0982d5d44272f0e612fd1f2a64e7e49ed7d20c1
URL: https://github.com/llvm/llvm-project/commit/f0982d5d44272f0e612fd1f2a64e7e49ed7d20c1 DIFF: https://github.com/llvm/llvm-project/commit/f0982d5d44272f0e612fd1f2a64e7e49ed7d20c1.diff LOG: [clang][bytecode] Fix calling lambdas with broken instance pointers (#175511) Clang will make the instance pointer be of type 'int' if it is invalid, which trips up later logic. Mark functions as invalid if any of their parameters is and compile + check them early in CallPtr. Fixes https://github.com/llvm/llvm-project/issues/175425 Added: Modified: clang/lib/AST/ByteCode/ByteCodeEmitter.cpp clang/lib/AST/ByteCode/Interp.cpp clang/test/AST/ByteCode/cxx23.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index f430b2329a6f3..5dc6eca582ad9 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -54,12 +54,15 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, } } + bool IsValid = !FuncDecl->isInvalidDecl(); // Register parameters with their offset. unsigned ParamIndex = 0; unsigned Drop = Func->hasRVO() + (Func->hasThisPointer() && !Func->isThisPointerExplicit()); for (auto ParamOffset : llvm::drop_begin(Func->ParamOffsets, Drop)) { const ParmVarDecl *PD = FuncDecl->parameters()[ParamIndex]; + if (PD->isInvalidDecl()) + IsValid = false; OptPrimType T = Ctx.classify(PD->getType()); this->Params.insert({PD, {ParamOffset, T != std::nullopt}}); ++ParamIndex; @@ -86,8 +89,7 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl, // Set the function's code. Func->setCode(FuncDecl, NextLocalOffset, std::move(Code), std::move(SrcMap), - std::move(Scopes), FuncDecl->hasBody(), - !FuncDecl->isInvalidDecl()); + std::move(Scopes), FuncDecl->hasBody(), IsValid); Func->setIsFullyCompiled(true); } diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 7e901aa65af1c..b5a66ff6fbab3 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -1869,6 +1869,15 @@ bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, return false; } + // We nedd to compile (and check) early for function pointer calls + // because the Call/CallVirt below might access the instance pointer + // but the Function's information about them is wrong. + if (!F->isFullyCompiled()) + compileFunction(S, F); + + if (!CheckCallable(S, OpPC, F)) + return false; + assert(ArgSize >= F->getWrittenArgSize()); uint32_t VarArgSize = ArgSize - F->getWrittenArgSize(); diff --git a/clang/test/AST/ByteCode/cxx23.cpp b/clang/test/AST/ByteCode/cxx23.cpp index 4b87f44d14345..eb35cd904c6db 100644 --- a/clang/test/AST/ByteCode/cxx23.cpp +++ b/clang/test/AST/ByteCode/cxx23.cpp @@ -1,8 +1,8 @@ // UNSUPPORTED: target={{.*}}-zos{{.*}} // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=ref,ref20,all,all20 %s // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=ref,ref23,all,all23 %s -// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter -// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected23,all,all23 %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected,expected20,all,all20 %s -fexperimental-new-constant-interpreter +// RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions -Wno-deprecated-volatile -verify=expected,expected23,all,all23 %s -fexperimental-new-constant-interpreter #define assert_active(F) if (!__builtin_is_within_lifetime(&F)) (1/0); @@ -259,6 +259,15 @@ namespace ExplicitLambdaInstancePointer { constexpr int (*fp)(C) = b; static_assert(fp(1) == 1, ""); } + + /// Failure case. The instance pointer is of type int. + struct S2 { + constexpr K(auto) { } // all-error {{a type specifier is required for all declarations}} + }; + constexpr auto b = [](this K) { return 1; }; // all20-error {{explicit object parameters are incompatible with C++ standards before C++2b}} \ + // all-error {{unknown type name 'K'}} + constexpr int (*fp)(K) = b; // all-error {{unknown type name 'K'}} + static_assert(fp(1) == 1, ""); // expected-error {{not an integral constant expression}} } namespace TwosComplementShifts { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
