[clang] [clang-tools-extra] [clang][bytecode] Don't evaluate bound member function expressions in new constant interpreter (PR #194851)

via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 29 06:12:48 PDT 2026


https://github.com/cakgok updated https://github.com/llvm/llvm-project/pull/194851

>From 00d9cd705c499621d1c3118b43bf777afd7fd2d9 Mon Sep 17 00:00:00 2001
From: Cem <cemakgok at gmail.com>
Date: Wed, 29 Apr 2026 15:24:20 +0300
Subject: [PATCH] [clang][bytecode] Don't evaluate bound member function
 expressions in new constant interpreter

---
 .../clangd/unittests/HoverTests.cpp           | 12 +++++
 clang/lib/AST/ByteCode/Compiler.cpp           |  8 +++
 clang/unittests/AST/EvaluateAsRValueTest.cpp  | 51 +++++++++++++++++++
 3 files changed, 71 insertions(+)

diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 7b168b0bdca60..9ce244e05a024 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -5245,6 +5245,18 @@ TEST(Hover, FunctionParameters) {
   }
 }
 
+TEST(Hover, NoCrashOnBoundMemberFunctionWithNewInterpreter) {
+  Annotations Code(R"cpp(
+    struct S { void f(); };
+    void g() { S s; s.^f(); }
+  )cpp");
+  TestTU TU = TestTU::withCode(Code.code());
+  TU.ExtraArgs.push_back("-std=c++23");
+  TU.ExtraArgs.push_back("-fexperimental-new-constant-interpreter");
+  auto AST = TU.build();
+  getHover(AST, Code.point(), format::getLLVMStyle(), nullptr);
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index d4bbb8d3a8a3e..ca2a408c0eceb 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -2643,6 +2643,14 @@ bool Compiler<Emitter>::VisitMemberExpr(const MemberExpr *E) {
     if (!this->discard(Base) && !this->emitSideEffect(E))
       return false;
 
+    // Bound member functions (non-static CXXMethodDecls) cannot be
+    // constant-evaluated. visitDeclRef would blindly push a FnPtr,
+    // but the caller expects a MemberPointer, causing a stack mismatch.
+    if (const auto *MD = dyn_cast<CXXMethodDecl>(Member)) {
+      if (!MD->isStatic())
+        return false;
+    }
+
     return this->visitDeclRef(Member, E);
   }
 
diff --git a/clang/unittests/AST/EvaluateAsRValueTest.cpp b/clang/unittests/AST/EvaluateAsRValueTest.cpp
index 1e17330863f26..d98c1d09d5bd4 100644
--- a/clang/unittests/AST/EvaluateAsRValueTest.cpp
+++ b/clang/unittests/AST/EvaluateAsRValueTest.cpp
@@ -154,3 +154,54 @@ TEST(EvaluateAsRValue, LValueToRValueConversionWorks) {
                                       Args));
   }
 }
+
+class EvaluateBoundMemberFunctionVisitor
+    : public clang::DynamicRecursiveASTVisitor {
+public:
+  explicit EvaluateBoundMemberFunctionVisitor(clang::ASTContext &Ctx)
+      : Ctx(Ctx) {}
+
+  bool VisitMemberExpr(clang::MemberExpr *E) override {
+    if (llvm::isa<clang::CXXMethodDecl>(E->getMemberDecl())) {
+      clang::Expr::EvalResult Result;
+      bool EvalSucceeded = E->EvaluateAsRValue(Result, Ctx, true);
+      EXPECT_FALSE(EvalSucceeded);
+    }
+    return true;
+  }
+
+private:
+  clang::ASTContext &Ctx;
+};
+
+class EvaluateBoundMemberFunctionAction : public clang::ASTFrontendAction {
+public:
+  std::unique_ptr<clang::ASTConsumer>
+  CreateASTConsumer(clang::CompilerInstance &Compiler,
+                    llvm::StringRef FilePath) override {
+    return std::make_unique<Consumer>();
+  }
+
+private:
+  class Consumer : public clang::ASTConsumer {
+  public:
+    ~Consumer() override {}
+    void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+      EvaluateBoundMemberFunctionVisitor Evaluator(Ctx);
+      Evaluator.TraverseDecl(Ctx.getTranslationUnitDecl());
+    }
+  };
+};
+
+TEST(EvaluateAsRValue, FailsGracefullyOnBoundMemberExpr) {
+  std::string ModesToTest[] = {"", "-fexperimental-new-constant-interpreter"};
+  for (std::string const &Mode : ModesToTest) {
+    std::vector<std::string> Args(1, Mode);
+    Args.push_back("-std=c++23");
+    ASSERT_TRUE(runToolOnCodeWithArgs(
+        std::make_unique<EvaluateBoundMemberFunctionAction>(),
+        "struct S { void f(); };\n"
+        "void g() { S s; s.f(); }\n",
+        Args));
+  }
+}



More information about the cfe-commits mailing list