https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/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 >From 4292d9da198467f64fffdcbaf92a0d22e0283938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <[email protected]> Date: Mon, 12 Jan 2026 11:16:22 +0100 Subject: [PATCH] [clang][bytecode] Fix calling lambdas with broken instance pointers 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 --- clang/lib/AST/ByteCode/ByteCodeEmitter.cpp | 6 ++++-- clang/lib/AST/ByteCode/Interp.cpp | 9 +++++++++ clang/test/AST/ByteCode/cxx23.cpp | 13 +++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) 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
