https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125712
Bug ID: 125712
Summary: [contracts] ICE in tsubst_contract_specifiers with a
contract on an out-of-line member template function
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: vincent.liu at arista dot com
Target Milestone: ---
Specifying a contract on an out-of-line templated member function causes an
ICE.
The ICE disappears if the function definitions are moved inside the struct.
I noticed there are some existing bugs filed against contract/template
interactions, but the call stack on this is a bit different. Apologies if this
ends up being a duplicate.
---
Output of `gcc -v`
```
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/opt/gcc-16/libexec/gcc/x86_64-redhat-linux/16.1.0/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../gcc-16.1.0/configure --prefix=/opt/gcc-16
--enable-languages=c,c++ --enable-libstdcxx-backtrace --disable-multilib
--build=x86_64-redhat-linux
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 16.1.0 (GCC)
```
Minimally reproducing code (flags: -std=c++26 -fcontracts)
```
bool check(int) { return true; }
struct Foo {
template <typename T>
void func1(int p);
template <typename T>
void func2(int p) pre(check(p));
};
template <typename T>
void Foo::func1(int p) {
func2<int>(p);
}
template <typename T>
void Foo::func2(int p) {}
int main() {
Foo().func1<int>(0);
return 0;
}
```
---
Compiler output
```
test.cpp: In instantiation of ‘void Foo::func2(int) [with T = int]’:
test.cpp:13:15: required from ‘void Foo::func1(int) [with T = int]’
13 | func2<int>(p);
| ~~~~~~~~~~^~~
test.cpp:20:21: required from here
20 | Foo().func1<int>(0);
| ~~~~~~~~~~~~~~~~^~~
test.cpp:8:33: internal compiler error: in tsubst_expr, at cp/pt.cc:22894
8 | void func2(int p) pre(check(p));
| ^
0x244923f internal_error(char const*, ...)
../../gcc-16.1.0/gcc/diagnostic-global-context.cc:787
0x8453c7 fancy_abort(char const*, int, char const*)
../../gcc-16.1.0/gcc/diagnostics/context.cc:1813
0x7f921a tsubst_expr(tree_node*, tree_node*, int, tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:22894
0xa505a9 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:21376
0xa505a9 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:23303
0xa6bcbd tsubst_expr(tree_node*, tree_node*, int, tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:21376
0xa6bcbd tsubst_call_args
../../gcc-16.1.0/gcc/cp/pt.cc:21335
0xa4fa59 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:22226
0xa55dd0 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:21376
0xa55dd0 tsubst_contract
../../gcc-16.1.0/gcc/cp/pt.cc:12283
0xa5607e tsubst_contract_specifier
../../gcc-16.1.0/gcc/cp/pt.cc:12340
0xa5607e tsubst_contract_specifiers(tree_node*, tree_node*, tree_node*, int,
tree_node*)
../../gcc-16.1.0/gcc/cp/pt.cc:12361
0xa5c650 regenerate_decl_from_template
../../gcc-16.1.0/gcc/cp/pt.cc:28290
0xa5c650 instantiate_body
../../gcc-16.1.0/gcc/cp/pt.cc:28621
0xa5cfa5 instantiate_decl(tree_node*, bool, bool)
../../gcc-16.1.0/gcc/cp/pt.cc:28979
0xa7e0cb instantiate_pending_templates(int)
../../gcc-16.1.0/gcc/cp/pt.cc:29054
0x9234b6 c_parse_final_cleanups()
../../gcc-16.1.0/gcc/cp/decl2.cc:5887
0xb63aa0 c_common_parse_file()
../../gcc-16.1.0/gcc/c-family/c-opts.cc:1448
/opt/gcc-16/libexec/gcc/x86_64-redhat-linux/16.1.0/cc1plus -fpreprocessed
a-test.ii -quiet -dumpdir a- -dumpbase test.cpp -dumpbase-ext .cpp
-mtune=generic -march=x86-64 -std=c++26 -fcontracts -freport-bug -o a-test.s
Please submit a full bug report, with preprocessed source.
Please include the complete backtrace with any bug report.
See <https://gcc.gnu.org/bugs/> for instructions.
Preprocessed source stored into /tmp/ccBrFNSI.out file, please attach this to
your bugreport.
```
---
Preprocessed source (this was generated on gcc 16.1)
```
// Target: x86_64-redhat-linux
// Configured with: ../gcc-16.1.0/configure --prefix=/opt/gcc-16
--enable-languages=c,c++ --enable-libstdcxx-backtrace --disable-multilib
--build=x86_64-redhat-linux
// Thread model: posix
// Supported LTO compression algorithms: zlib
// gcc version 16.1.0 (GCC)
//
// test.cpp: In instantiation of ‘void Foo::func2(int) [with T = int]’:
// test.cpp:13:15: required from ‘void Foo::func1(int) [with T = int]’
// 13 | func2<int>(p);
// | ~~~~~~~~~~^~~
// test.cpp:20:21: required from here
// 20 | Foo().func1<int>(0);
// | ~~~~~~~~~~~~~~~~^~~
// test.cpp:8:33: internal compiler error: in tsubst_expr, at cp/pt.cc:22894
// 8 | void func2(int p) pre(check(p));
// | ^
// 0x244923f internal_error(char const*, ...)
// ../../gcc-16.1.0/gcc/diagnostic-global-context.cc:787
// 0x8453c7 fancy_abort(char const*, int, char const*)
// ../../gcc-16.1.0/gcc/diagnostics/context.cc:1813
// 0x7f921a tsubst_expr(tree_node*, tree_node*, int, tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:22894
// 0xa505a9 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:21376
// 0xa505a9 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:23303
// 0xa6bcbd tsubst_expr(tree_node*, tree_node*, int, tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:21376
// 0xa6bcbd tsubst_call_args
// ../../gcc-16.1.0/gcc/cp/pt.cc:21335
// 0xa4fa59 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:22226
// 0xa55dd0 tsubst_expr(tree_node*, tree_node*, int, tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:21376
// 0xa55dd0 tsubst_contract
// ../../gcc-16.1.0/gcc/cp/pt.cc:12283
// 0xa5607e tsubst_contract_specifier
// ../../gcc-16.1.0/gcc/cp/pt.cc:12340
// 0xa5607e tsubst_contract_specifiers(tree_node*, tree_node*, tree_node*, int,
tree_node*)
// ../../gcc-16.1.0/gcc/cp/pt.cc:12361
// 0xa5c650 regenerate_decl_from_template
// ../../gcc-16.1.0/gcc/cp/pt.cc:28290
// 0xa5c650 instantiate_body
// ../../gcc-16.1.0/gcc/cp/pt.cc:28621
// 0xa5cfa5 instantiate_decl(tree_node*, bool, bool)
// ../../gcc-16.1.0/gcc/cp/pt.cc:28979
// 0xa7e0cb instantiate_pending_templates(int)
// ../../gcc-16.1.0/gcc/cp/pt.cc:29054
// 0x9234b6 c_parse_final_cleanups()
// ../../gcc-16.1.0/gcc/cp/decl2.cc:5887
// 0xb63aa0 c_common_parse_file()
// ../../gcc-16.1.0/gcc/c-family/c-opts.cc:1448
// -fpreprocessed a-test.ii -quiet -dumpdir a- -dumpbase test.cpp -dumpbase-ext
.cpp -mtune=generic -march=x86-64 -std=c++26 -fcontracts -freport-bug -o -
-frandom-seed=0 -fdump-noaddr
// Please submit a full bug report, with preprocessed source.
// Please include the complete backtrace with any bug report.
// See <https://gcc.gnu.org/bugs/> for instructions.
// /opt/gcc-16/libexec/gcc/x86_64-redhat-linux/16.1.0/cc1plus -fpreprocessed
a-test.ii -quiet -dumpdir a- -dumpbase test.cpp -dumpbase-ext .cpp
-mtune=generic -march=x86-64 -std=c++26 -fcontracts -freport-bug -o -
-frandom-seed=0 -fdump-noaddr
# 0 "a-test.ii"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3
# 0 "<command-line>" 2
# 1 "a-test.ii"
# 0 "test.cpp"
# 0 "<built-in>"
# 0 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3
# 0 "<command-line>" 2
# 1 "test.cpp"
bool check(int) { return true; }
struct Foo {
template <typename T>
void func1(int p);
template <typename T>
void func2(int p) pre(check(p));
};
template <typename T>
void Foo::func1(int p) {
func2<int>(p);
}
template <typename T>
void Foo::func2(int p) {}
int main() {
Foo().func1<int>(0);
return 0;
}
```
---
I also created a self-contained reproduction on godbolt. This repro's on gcc
16.1 as well as gcc trunk (17).
https://godbolt.org/z/7MqehrMer