llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Anutosh Bhat (anutosh491) <details> <summary>Changes</summary> Fixes https://github.com/compiler-research/xeus-cpp/issues/431 When a function template is instantiated in clang-repl and the instantiation fails (e.g. a `static_assert` in the body), the session becomes poisoned for the rest of the interaction. Any subsequent cell — even completely unrelated ones like `int x = 10;` — would fail with a JIT "Symbols not found" error. The root cause is a timing issue between when codegen emits IR and when the error actually fires. When you call something like `f(1.0)` where f is a non-constexpr function template, clang doesn't instantiate the body immediately. It queues the instantiation as "deferred" and the parse loop moves on. At this point, codegen has already emitted a call instruction to `f<double>` into the current LLVM module — because the call expression was processed before any error fired. The instantiation happens later, inside `ParseTopLevelDecl` when it hits `end-of-input `and calls `ActOnEndOfTranslationUnit` → `PerformPendingInstantiations`. That's where the `static_assert` fires. By then, the `InProcessPrintingASTConsumer `guard (`if (Diags.hasErrorOccurred())` return early) kicks in and the function body never reaches CodeGen. So the module ends up with a call to a symbol that has no definition. I dumped Modules while executing code to show the same ``` clang-repl> #include <type_traits> clang-repl> #include <iostream> clang-repl> template<typename T> T integral_div(T a, T b) { static_assert(std::is_integral<T>::value, "not an integral type"); return a / b; } clang-repl> clang-repl> integral_div<double>(8.0, 2.0) In file included from <<< inputs >>>:1: input_line_3:1:78: error: static assertion failed due to requirement 'std::is_integral<double>::value': not an integral type 1 | ...integral_div(T a, T b) { static_assert(std::is_integral<T>::value, "not a... | ^~~~~~~~~~~~~~~~~~~~~~~~~~ input_line_4:1:1: note: in instantiation of function template specialization 'integral_div<double>' requested here 1 | integral_div<double>(8.0, 2.0) | ^ [clang-repl] parse error: module IR before cleanup --- ; ModuleID = 'incr_module_4' source_filename = "incr_module_4" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" target triple = "arm64-apple-macosx26.0.0" define internal void @<!-- -->__stmts__0() { %1 = bitcast i32 poison to i32 %2 = call noundef double @<!-- -->_Z12integral_divIdET_S0_S0_(double noundef 8.000000e+00, double noundef 2.000000e+00) call void (ptr, ptr, ptr, ...) @<!-- -->__clang_Interpreter_SetValueNoAlloc(ptr noundef inttoptr (i64 4547296960 to ptr), ptr noundef inttoptr (i64 4547297048 to ptr), ptr noundef inttoptr (i64 37670594624 to ptr), double noundef %2) } declare void @<!-- -->__clang_Interpreter_SetValueNoAlloc(ptr noundef, ptr noundef, ptr noundef, ...) #<!-- -->0 declare noundef double @<!-- -->_Z12integral_divIdET_S0_S0_(double noundef, double noundef) #<!-- -->0 attributes #<!-- -->0 = { "frame-pointer"="non-leaf-no-reserve" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+ccpp,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" "tune-cpu"="apple-m5" } !llvm.module.flags = !{!0} !0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 5]} [clang-repl] --- end module --- error: Parsing failed. clang-repl> clang-repl> clang-repl> int x = 10; [clang-repl] module registered for PTU 4 (incr_module_4) --- ; ModuleID = 'incr_module_4' source_filename = "incr_module_4" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32" target triple = "arm64-apple-macosx26.0.0" @<!-- -->x = global i32 10, align 4 @<!-- -->llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @<!-- -->_GLOBAL__sub_I_incr_module_4, ptr null }] define internal void @<!-- -->__stmts__0() { %1 = call noundef double @<!-- -->_Z12integral_divIdET_S0_S0_(double noundef 8.000000e+00, double noundef 2.000000e+00) call void (ptr, ptr, ptr, ...) @<!-- -->__clang_Interpreter_SetValueNoAlloc(ptr noundef inttoptr (i64 4547296960 to ptr), ptr noundef inttoptr (i64 4547297048 to ptr), ptr noundef inttoptr (i64 37670594624 to ptr), double noundef %1) ret void } declare void @<!-- -->__clang_Interpreter_SetValueNoAlloc(ptr noundef, ptr noundef, ptr noundef, ...) #<!-- -->0 declare noundef double @<!-- -->_Z12integral_divIdET_S0_S0_(double noundef, double noundef) #<!-- -->0 ; Function Attrs: noinline ssp uwtable(sync) define internal void @<!-- -->_GLOBAL__sub_I_incr_module_4() #<!-- -->1 section "__TEXT,__StaticInit,regular,pure_instructions" { call void @<!-- -->__stmts__0() ret void } attributes #<!-- -->0 = { "frame-pointer"="non-leaf-no-reserve" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+ccpp,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" "tune-cpu"="apple-m5" } attributes #<!-- -->1 = { noinline ssp uwtable(sync) "frame-pointer"="non-leaf-no-reserve" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+altnzcv,+ccdp,+ccidx,+ccpp,+complxnum,+crc,+dit,+dotprod,+flagm,+fp-armv8,+fp16fml,+fptoint,+fullfp16,+jsconv,+lse,+neon,+pauth,+perfmon,+predres,+ras,+rcpc,+rdm,+sb,+sha2,+sha3,+specrestrict,+ssbs,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8a" "tune-cpu"="apple-m5" } !llvm.module.flags = !{!0, !1, !2, !3} !llvm.ident = !{!4} !0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 5]} !1 = !{i32 8, !"PIC Level", i32 2} !2 = !{i32 7, !"uwtable", i32 1} !3 = !{i32 7, !"frame-pointer", i32 4} !4 = !{!"clang version 23.0.0git (git@<!-- -->github.com:anutosh491/llvm-project.git 8abb6c1f71112016c9252ebfb19fd388a12b691e)"} [clang-repl] --- end PTU module --- JIT session error: Symbols not found: [ __Z12integral_divIdET_S0_S0_ ] error: Failed to materialize symbols: { (main, { _x, $.incr_module_4.__inits.0, ____orc_init_func.incr_module_4 }) } ``` As can be seen `__stmts__0` carrying `_Z12integral_divIdET_S0_S0_` is also a part of the IR generated from the next cell which is `int x = 10` --- Full diff: https://github.com/llvm/llvm-project/pull/204152.diff 4 Files Affected: - (modified) clang/lib/Interpreter/IncrementalAction.cpp (+3-2) - (modified) clang/lib/Interpreter/IncrementalAction.h (+2) - (modified) clang/lib/Interpreter/IncrementalParser.cpp (+3-1) - (added) clang/test/Interpreter/recover-template-instantiation.cpp (+22) ``````````diff diff --git a/clang/lib/Interpreter/IncrementalAction.cpp b/clang/lib/Interpreter/IncrementalAction.cpp index d22031c8fa893..d9a7de25af147 100644 --- a/clang/lib/Interpreter/IncrementalAction.cpp +++ b/clang/lib/Interpreter/IncrementalAction.cpp @@ -53,7 +53,7 @@ IncrementalAction::IncrementalAction(CompilerInstance &Instance, } return Act; }()), - Interp(I), CI(Instance), Consumer(std::move(Consumer)) {} + Interp(I), CI(Instance), LLVMCtx(LLVMCtx), Consumer(std::move(Consumer)) {} std::unique_ptr<ASTConsumer> IncrementalAction::CreateASTConsumer(CompilerInstance & /*CI*/, @@ -114,7 +114,8 @@ std::unique_ptr<llvm::Module> IncrementalAction::GenModule() { CachedInCodeGenModule->ifunc_empty())) && "CodeGen wrote to a readonly module"); std::unique_ptr<llvm::Module> M(CG->ReleaseModule()); - CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext()); + CG->StartModule("incr_module_" + std::to_string(ID++), + M ? M->getContext() : LLVMCtx); return M; } return nullptr; diff --git a/clang/lib/Interpreter/IncrementalAction.h b/clang/lib/Interpreter/IncrementalAction.h index 725cdd0c27cf4..27daf15d8c91e 100644 --- a/clang/lib/Interpreter/IncrementalAction.h +++ b/clang/lib/Interpreter/IncrementalAction.h @@ -13,6 +13,7 @@ #include "clang/Frontend/MultiplexConsumer.h" namespace llvm { +class LLVMContext; class Module; } @@ -35,6 +36,7 @@ class IncrementalAction : public WrapperFrontendAction { bool IsTerminating = false; Interpreter &Interp; [[maybe_unused]] CompilerInstance &CI; + llvm::LLVMContext &LLVMCtx; std::unique_ptr<ASTConsumer> Consumer; /// When CodeGen is created the first llvm::Module gets cached in many places diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index f6d2779d64b2b..b3af640f3cb21 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -85,7 +85,9 @@ IncrementalParser::ParseOrWrapTopLevelDecl() { DiagnosticsEngine &Diags = S.getDiagnostics(); if (Diags.hasErrorOccurred()) { CleanUpPTU(C.getTranslationUnitDecl()); - + // Discard any partial CodeGen state to avoid contaminating the next cell. + Consumer->HandleTranslationUnit(C); + Act->GenModule(); Diags.Reset(/*soft=*/true); Diags.getClient()->clear(); return llvm::make_error<llvm::StringError>("Parsing failed.", diff --git a/clang/test/Interpreter/recover-template-instantiation.cpp b/clang/test/Interpreter/recover-template-instantiation.cpp new file mode 100644 index 0000000000000..0cf8564cc8fe2 --- /dev/null +++ b/clang/test/Interpreter/recover-template-instantiation.cpp @@ -0,0 +1,22 @@ +// REQUIRES: host-supports-jit +// RUN: cat %s | clang-repl 2>&1 | FileCheck %s + +// Verify that clang-repl recovers cleanly after a deferred template +// instantiation error. The failed cell must not contaminate the CodeGen module +// used by subsequent cells. + +extern "C" int printf(const char *, ...); + +template <typename T> T f(T a) { + static_assert(sizeof(T) == 0, "unsupported type"); + return a; +} + +f(1.0); +// CHECK: error: static assertion failed + +int x = 10; +auto r = printf("x = %d\n", x); +// CHECK: x = 10 + +%quit `````````` </details> https://github.com/llvm/llvm-project/pull/204152 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
