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

            Bug ID: 125537
           Summary: [contracts] g++-16 crashes on contracts pre and post
                    with auto parameters
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: igor.machado at gmail dot com
  Target Milestone: ---

I'm testing some code with Cxx contracts from C++26 on Ubuntu 26.04, and g++
16.0.1 crashes on contracts that have auto parameters. It can be solved with
explicit template parameters, so it's not a real issue, but I'm reporting
anyway for the progress of GCC and CXX Contracts.

This is the problematic source code and crash report (I tried to make it as
minimal as I could):

struct NoEnc {
   NoEnc* esq; 
   NoEnc* dir;  
};

auto* minimo(auto* const no) 
pre(no)
// post(out : !out->esq) 
{
  auto* atual = no;
  while(atual->esq) atual = atual->esq;
  return atual;
};

int main() { 
    auto* no = new NoEnc{.esq=0, .dir=0};
    auto* no2 = minimo(no);
    return 0;
}

g++-16  -std=c++26 -fcontracts gcc_bug.cpp -freport-bug -o app_bug
during GIMPLE pass: local-fnsummary
gcc_bug.cpp: In function ‘auto* minimo(auto:1*) [with auto:1 = NoEnc]’:
gcc_bug.cpp:20:1: internal compiler error: in estimate_operator_cost, at
tree-inline.cc:4433
   20 | }
      | ^
0x175b4d4 internal_error(char const*, ...)
        ../../src/gcc/diagnostic-global-context.cc:787
0x175f96b fancy_abort(char const*, int, char const*)
        ../../src/gcc/diagnostics/context.cc:1813
0xa6ae38 estimate_operator_cost(tree_code, eni_weights*, tree_node*,
tree_node*) [clone .constprop.1]
        ../../src/gcc/tree-inline.cc:4433
0x1b04dbc estimate_num_insns(gimple*, eni_weights*) [clone .constprop.1]
        ../../src/gcc/tree-inline.cc:4503
0x1b67927 analyze_function_body(cgraph_node*, bool) [clone .constprop.0]
        ../../src/gcc/ipa-fnsummary.cc:3024
0x1b44f51 compute_fn_summary(cgraph_node*, bool) [clone .constprop.0]
        ../../src/gcc/ipa-fnsummary.cc:3518
0x1b41c5d compute_fn_summary_for_current
        ../../src/gcc/ipa-fnsummary.cc:3548
0x1b41c5d execute
        ../../src/gcc/ipa-fnsummary.cc:5219
/usr/libexec/gcc/x86_64-linux-gnu/16/cc1plus -quiet -imultiarch
x86_64-linux-gnu -D_GNU_SOURCE gcc_bug.cpp -quiet -dumpdir app_bug- -dumpbase
gcc_bug.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -std=c++26
-fcontracts -freport-bug -foffload-options=-l_GCC_stdc++
-foffload-options=-l_GCC_m -fasynchronous-unwind-tables
-fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection
-fcf-protection -fzero-init-padding-bits=all -Wbidi-chars=any -o
/tmp/ccyvDyom.s
Please submit a full bug report, with preprocessed source.
Please include the complete backtrace with any bug report.
See <file:///usr/share/doc/gcc-16/README.Bugs> for instructions.
=== BEGIN GCC DUMP ===
4059811: // Target: x86_64-linux-gnu
4059811: // Configured with: ../src/configure -v --with-pkgversion='Ubuntu
16-20260322-1ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-16/README.Bugs
--enable-languages=c,ada,c++,go,d,fortran,objc,obj-c++,m2,rust,cobol,algol68
--prefix=/usr --with-gcc-major-version-only --program-suffix=-16
--program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id
--libexecdir=/usr/libexec --without-included-gettext --enable-threads=posix
--libdir=/usr/lib --enable-nls --enable-bootstrap --enable-clocale=gnu
--enable-libstdcxx-debug --enable-libstdcxx-time=yes
--with-default-libstdcxx-abi=new --enable-libstdcxx-backtrace
--enable-gnu-unique-object --disable-vtable-verify --enable-plugin
--enable-default-pie --with-system-zlib --enable-libphobos-checking=release
--with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch
--disable-werror --enable-cet --with-arch-32=i686 --with-abi=m64
--with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic
--enable-offload-targets=nvptx-none=/build/gcc-16-UBzkgO/gcc-16-16-20260322/debian/tmp-nvptx/usr,amdgcn-amdhsa=/build/gcc-16-UBzkgO/gcc-16-16-20260322/debian/tmp-gcn/usr
--enable-offload-defaulted --without-cuda-driver --enable-checking=release
--build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
--with-build-config=bootstrap-lto-lean --enable-link-serialization=2
4059811: // Thread model: posix
4059811: // Supported LTO compression algorithms: zlib zstd
4059811: // gcc version 16.0.1 20260322 (experimental) [trunk
r16-8246-g569ace1fa50] (Ubuntu 16-20260322-1ubuntu1) 
4059811: // 
4059811: // during GIMPLE pass: local-fnsummary
4059811: // gcc_bug.cpp: In function ‘auto* minimo(auto:1*) [with auto:1 =
NoEnc]’:
4059811: // gcc_bug.cpp:20:1: internal compiler error: in
estimate_operator_cost, at tree-inline.cc:4433
4059811: //    20 | }
4059811: //       | ^
4059811: // 0x175b4d4 internal_error(char const*, ...)
4059811: //     ../../src/gcc/diagnostic-global-context.cc:787
4059811: // 0x175f96b fancy_abort(char const*, int, char const*)
4059811: //     ../../src/gcc/diagnostics/context.cc:1813
4059811: // 0xa6ae38 estimate_operator_cost(tree_code, eni_weights*,
tree_node*, tree_node*) [clone .constprop.1]
4059811: //     ../../src/gcc/tree-inline.cc:4433
4059811: // 0x1b04dbc estimate_num_insns(gimple*, eni_weights*) [clone
.constprop.1]
4059811: //     ../../src/gcc/tree-inline.cc:4503
4059811: // 0x1b67927 analyze_function_body(cgraph_node*, bool) [clone
.constprop.0]
4059811: //     ../../src/gcc/ipa-fnsummary.cc:3024
4059811: // 0x1b44f51 compute_fn_summary(cgraph_node*, bool) [clone
.constprop.0]
4059811: //     ../../src/gcc/ipa-fnsummary.cc:3518
4059811: // 0x1b41c5d compute_fn_summary_for_current
4059811: //     ../../src/gcc/ipa-fnsummary.cc:3548
4059811: // 0x1b41c5d execute
4059811: //     ../../src/gcc/ipa-fnsummary.cc:5219
4059811: // -quiet -imultiarch x86_64-linux-gnu -D_GNU_SOURCE gcc_bug.cpp
-quiet -dumpdir app_bug- -dumpbase gcc_bug.cpp -dumpbase-ext .cpp
-mtune=generic -march=x86-64 -std=c++26 -fcontracts -freport-bug
-foffload-options=-l_GCC_stdc++ -foffload-options=-l_GCC_m
-fasynchronous-unwind-tables -fstack-protector-strong -Wformat
-Wformat-security -fstack-clash-protection -fcf-protection
-fzero-init-padding-bits=all -Wbidi-chars=any -o - -frandom-seed=0
-fdump-noaddr
4059811: // Please submit a full bug report, with preprocessed source.
4059811: // Please include the complete backtrace with any bug report.
4059811: // See <file:///usr/share/doc/gcc-16/README.Bugs> for instructions.
4059811: 
4059811: // /usr/libexec/gcc/x86_64-linux-gnu/16/cc1plus -quiet -imultiarch
x86_64-linux-gnu -D_GNU_SOURCE gcc_bug.cpp -quiet -dumpdir app_bug- -dumpbase
gcc_bug.cpp -dumpbase-ext .cpp -mtune=generic -march=x86-64 -std=c++26
-fcontracts -freport-bug -foffload-options=-l_GCC_stdc++
-foffload-options=-l_GCC_m -fasynchronous-unwind-tables
-fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection
-fcf-protection -fzero-init-padding-bits=all -Wbidi-chars=any -o -
-frandom-seed=0 -fdump-noaddr
4059811: 
4059811: # 0 "gcc_bug.cpp"
4059811: # 0 "<built-in>"
4059811: # 0 "<command-line>"
4059811: # 1 "/usr/include/stdc-predef.h" 1 3
4059811: # 0 "<command-line>" 2
4059811: # 1 "gcc_bug.cpp"
4059811: 
4059811: struct NoEnc {
4059811:    NoEnc* esq;
4059811:    NoEnc* dir;
4059811: };
4059811: 
4059811: auto* minimo(auto* const no)
4059811: pre(no)
4059811: 
4059811: {
4059811:   auto* atual = no;
4059811:   while(atual->esq) atual = atual->esq;
4059811:   return atual;
4059811: };
4059811: 
4059811: int main() {
4059811:     auto* no = new NoEnc{.esq=0, .dir=0};
4059811:     auto* no2 = minimo(no);
4059811:     return 0;
4059811: }
=== END GCC DUMP ===

The bug is connected with having "auto" on parameters with pre and post, but
the precise behavior is a little strange.
When both parameters have auto*, and only pre, it breaks!

auto* minimo(auto* const no) 
pre(no)
// post(out : !out->esq) 

When the input auto is resolved to an explicit type and post is added, it does
not crash, but complains that "post" cannot be auto* (maybe some rule from CXX
Contracts that I violated):

auto* minimo(NoEnc* const no) 
pre(no)
post(out : !out->esq) 
{
  auto* atual = no;
  while(atual->esq) atual = atual->esq;
  return atual;
};

g++-16  -std=c++26 -fcontracts gcc_bug.cpp -freport-bug -o app_bug
gcc_bug.cpp:9:18: error: invalid use of ‘auto’
    9 | post(out : !out->esq)
      |             ~~~~~^~~
make: *** [Makefile:4: gcc_bug] Error 1

Finally, when auto* return parameters is resolved, but auto* is kept on input
parameter, it does not crash on pre():

NoEnc* minimo(auto* const no) 
pre(no)
post(out : !out->esq) 

So, my conclusion is that "pre" only breaks if BOTH input and output parameters
are auto*.

A better solution is to use explicit template parameters, like this, that does
not break:

template <typename X>
X* minimo(X* const no)
pre(no)
post(out : !out->esq) 
{
  auto* atual = no;
  while(atual->esq) atual = atual->esq;
  return atual;
};

I only tested g++ 16.0.1 because it's latest on Ubuntu 26.04, haven't tried on
latest ones like 16.1 and 17.0.

$ g++-16 --version
g++-16 (Ubuntu 16-20260322-1ubuntu1) 16.0.1 20260322 (experimental) [trunk
r16-8246-g569ace1fa50]

Best regards and congratulations for this amazing project!
Good luck!

Reply via email to