https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124264

            Bug ID: 124264
           Summary: [contracts] __tu_has_violation internal linkage causes
                    undefined reference with modules on MinGW/PE-COFF
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: libstdc++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: kachalenko.denis at gmail dot com
  Target Milestone: ---

When a non-template inline function with a pre() contract is defined in a
module
interface, the compiler generates a COMDAT section for it in the consumer TU.
This COMDAT references __tu_has_violation from the module TU. However,
__tu_has_violation has internal linkage (TREE_PUBLIC=false in
declare_one_violation_handler_wrapper), so the linker fails with an undefined
reference on PE-COFF targets.

Template functions work because they are instantiated per-TU, which triggers
local emission of __tu_has_violation.

Note: handle_contract_violation is provided via handler.cpp to isolate this
bug from Bug 124263.

--- mod.cppm ---

export module M;
import std;
export struct Box {
    int D[4] = {};
    constexpr int operator[](int I) const noexcept
        pre(I >= 0 && I < 4)
    { return D[I]; }
};

--- main.cpp ---

import M;
import std;
int main() { Box b; std::cout << b[0]; }

--- handler.cpp ---

import std;
extern "C++" void handle_contract_violation(
    const std::contracts::contract_violation&) { std::abort(); }

--- commands ---

$ g++ -std=c++26 -fmodules -fcontracts -fcontract-evaluation-semantic=enforce \
    -c <gcc-install>/include/c++/16.0.1/bits/std.cc
$ g++ -std=c++26 -fmodules -fcontracts -fcontract-evaluation-semantic=enforce \
    -c mod.cppm -o mod.o
$ g++ -std=c++26 -fmodules -fcontracts -fcontract-evaluation-semantic=enforce \
    -c main.cpp -o main.o
$ g++ -std=c++26 -fmodules -fcontracts -fcontract-evaluation-semantic=enforce \
    -c handler.cpp -o handler.o
$ g++ mod.o main.o handler.o -o test.exe

--- expected ---

Links successfully.

--- actual ---

ld: main.o:main.cpp:(.text$_ZNKW1M3BoxixEi[_ZNKW1M3BoxixEi]+0x2b): undefined
reference to `__tu_has_violation(__builtin_contract_violation_type const&,
unsigned short)'
collect2.exe: error: ld returned 1 exit status

--- analysis ---

nm mod.o shows __tu_has_violation as 't' (local text):
  000000000000000e t
_Z18__tu_has_violationRK33__builtin_contract_violation_typet

nm main.o shows it as 'U' (undefined):
                   U
_Z18__tu_has_violationRK33__builtin_contract_violation_typet

The COMDAT section .text$_ZNKW1M3BoxixEi in main.o has a relocation to the
named symbol __tu_has_violation, but the symbol only exists in mod.o with
internal linkage.

A template version of the same struct links successfully because template
instantiation happens in the consumer TU, triggering per-TU emission of
__tu_has_violation.

Additionally, forcing __tu_has_violation emission via contract_assert(true) in
the consumer causes a secondary issue: the COMDAT relocation changes from a
named symbol reference to a section-relative .text reference, which is invalid
for COMDAT sections.

--- gcc -v ---

Using built-in specs.
Target: x86_64-w64-mingw32
Configured with: ../gcc-source/configure --prefix=/home/kacha/gcc-trunk-install
--build=x86_64-w64-mingw32 --host=x86_64-w64-mingw32
--target=x86_64-w64-mingw32 --enable-languages=c,c++ --enable-threads=posix
--enable-shared --enable-static --enable-lto --enable-plugin
--enable-checking=release --disable-multilib --disable-nls --disable-werror
--disable-bootstrap --with-tune=native --with-system-zlib --with-zstd
--with-native-system-header-dir=/ucrt64/include
Thread model: posix
gcc version 16.0.1 20260221 (experimental) (GCC)
Linker: GNU ld (GNU Binutils) 2.46

Related to Bug 119061 (P2900 Contracts tracker).

Reply via email to