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

Reply via email to