https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128127
Bug ID: 128127
Summary: ICE: verify_cgraph_node failed with invalid
calls_comdat_local flag at -O3
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: ice-checking, ice-on-valid-code
Severity: normal
Priority: P3
Component: ipa
Assignee: unassigned at gcc dot gnu.org
Reporter: yqtian668 at gmail dot com
Target Milestone: ---
Host: x86_64-pc-linux-gnu
Target: x86_64-pc-linux-gnu
Build: x86_64-pc-linux-gnu
Created attachment 65948
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65948&action=edit
Preprocessed C++ testcase
A checking-enabled GCC trunk build aborts during the IPA inline pass while
compiling this valid C++ program at -O3. The verifier reports a stale
calls_comdat_local flag on the deleting destructor C3::~C3().
Reproducer:
static volatile unsigned in[] = {2435370849u, 1946221516u, 3880391396u,
398565419u, 2592673847u, 3612190063u, 2025886146u, 563125766u};
static unsigned checksum = 0;
static void mix(unsigned v) { checksum = checksum * 31u + v; }
namespace { struct C0; }
unsigned via_C0_f0(C0& r, unsigned a);
__attribute__((noinline)) unsigned nvia_C0_f0(C0& r, unsigned a);
__attribute__((noinline)) unsigned nvia_C0_f1(C0& r);
namespace {
struct C0 {
unsigned x0 = 2289764861u;
virtual ~C0() noexcept(false) {
mix(mc_C0_0());
mix(nvia_C0_f1(static_cast<C0&>(*this)));
}
__attribute__((noinline)) unsigned mc_C0_0() {
return nvia_C0_f0(static_cast<C0&>(*this), in[1]);
}
virtual unsigned f0(unsigned a) { return a * 1u + 53u; }
virtual unsigned f1() { return x0 * 747u + 362u; }
};
}
struct C1 : virtual C0 {};
struct C3 final : virtual C1, virtual C0 {
~C3() noexcept(false) try {
mix(via_C0_f0(static_cast<C0&>(*this), 7u));
} catch (...) { throw; }
unsigned f0(unsigned a) override { return a * 1u + 53u; }
};
unsigned via_C0_f0(C0& r, unsigned a) { return r.f0(a); }
__attribute__((noinline)) unsigned nvia_C0_f0(C0& r, unsigned a) {
return r.f0(a);
}
__attribute__((noinline)) unsigned nvia_C0_f1(C0& r) { return r.f1(); }
struct Hold_o0 { unsigned pad = 0u; C0 m; };
struct Hold_o2 { unsigned pad = 3u; C3 m; };
int main() {
{
Hold_o0 o0;
Hold_o2 o2;
C1 o3;
}
}
Command:
g++ -std=c++17 -O3 -c testcase.cpp
Actual behavior:
G++ reports 'error: invalid calls_comdat_local flag' for C3::~C3() and then
terminates with 'internal compiler error: verify_cgraph_node failed' during the
IPA inline pass. The first useful frame is optimize_inline_calls at
tree-inline.cc:5679.
Complete compiler output:
testcase.cpp: In destructor 'virtual C3::~C3()':
testcase.cpp:25:3: error: invalid calls_comdat_local flag
25 | ~C3() noexcept(false) try {
| ^
_ZN2C3D0Ev/22 (virtual C3::~C3())
Type: function definition analyzed
Visibility: externally_visible semantic_interposition public weak comdat
comdat_group:_ZN2C3D0Ev one_only section:.text._ZN2C3D0Ev (implicit_section)
virtual
Same comdat group as: _ZTv0_n24_N2C3D0Ev/28
previous sharing asm name: 115
Address is taken.
References:
Referring: _ZTV2C3/59 (addr)
Availability: available
Function flags: count:1073741824 (estimated locally) body calls_comdat_local
Called by:
Calls: _Z10nvia_C0_f1RN12_GLOBAL__N_12C0E.isra.0/102 (1073741824 (estimated
locally),1.00 per call) _ZN12_GLOBAL__N_12C07mc_C0_0Ev.constprop.1/97
(1073741824 (estimated locally),1.00 per call) _ZdlPvm/72 (0 (precise),0.00 per
call) _ZdlPvm/72 (1073741824 (estimated locally),1.00 per call)
during IPA pass: inline
testcase.cpp:25:3: internal compiler error: verify_cgraph_node failed
0x2b9120b internal_error(char const*, ...)
/src/gcc/diagnostic-global-context.cc:787
0xfe4280 cgraph_node::verify_node()
/src/gcc/cgraph.cc:4505
0xfd1444 symtab_node::verify()
/src/gcc/symtab.cc:1377
0x162d18a optimize_inline_calls(tree_node*)
/src/gcc/tree-inline.cc:5679
0x12b6b8b inline_transform(cgraph_node*)
/src/gcc/ipa-inline-transform.cc:870
0x1452d7e execute_one_ipa_transform_pass
/src/gcc/passes.cc:2327
0x1452d7e execute_all_ipa_transforms(bool)
/src/gcc/passes.cc:2390
0xfe9a70 cgraph_node::expand()
/src/gcc/cgraphunit.cc:1866
0xfe9a70 cgraph_node::expand()
/src/gcc/cgraphunit.cc:1826
0xfeb04a expand_all_functions
/src/gcc/cgraphunit.cc:2056
0xfeb04a symbol_table::compile()
/src/gcc/cgraphunit.cc:2434
0xfedc16 symbol_table::compile()
/src/gcc/cgraphunit.cc:2344
0xfedc16 symbol_table::finalize_compilation_unit()
/src/gcc/cgraphunit.cc:2625
/opt/gcc/libexec/gcc/x86_64-pc-linux-gnu/17.0.0/cc1plus -quiet -imultiarch
x86_64-linux-gnu -D_GNU_SOURCE testcase.cpp -quiet -dumpbase testcase.cpp
-dumpbase-ext .cpp -mtune=generic -march=x86-64 -O3 -std=c++17 -o
/tmp/cc7p2g43.s
Please submit a full bug report, with preprocessed source (by using
-freport-bug).
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Expected behavior:
G++ should compile the valid C++ translation unit without an internal compiler
error.
The same compiler succeeds with -O2. It also succeeds at -O3 -fchecking=0, and
Clang trunk compiles the testcase at -O3. Adding -Wall -Wextra
-D_GLIBCXX_ASSERTIONS preserves the same ICE without producing a source-level
warning.
Compiler version:
g++ (GCC) 17.0.0 20261021 (experimental)
GCC revision 8cc6e7178c2e3b6156d7992bd18285be0da3c92c
Target: x86_64-pc-linux-gnu
Configured with: /src/configure --prefix=/opt/gcc --enable-languages=c,c++
--disable-multilib --disable-bootstrap --enable-checking=yes
Suspected cause:
calls_comdat_local is a cached callgraph property. gimple_expand_calls_inline
materializes the planned inline tree and removes the last comdat-local call
path from the outer deleting destructor, but the cached flag remains true.
optimize_inline_calls calls id.dst_node->verify() immediately afterward. The
recomputation added for PR94582 occurs later, so the early verifier sees the
stale value and aborts before that repair runs.
PR112601 has the opposite mismatch direction: its stored flag is false and
recomputation returns true. In this testcase, the node dump shows that the
stored flag is true, while verifier failure means recomputation returned false.