This is a little hard to explain clearly, but I'll do my best. I have a container class that I want to make properly allocator aware and ran into this ICE. When I don't use allocator_traits, and directly copy the allocator, it works just fine. But once I introduce the usage of allocator_traits<A>::select_on_container_copy_construction, I get an ICE. Example A (Works Properly): #include <memory> template <class T, class A = std::allocator<T>> struct MyType { MyType(const MyType &other) : a_(other.a_) { } MyType(const A &a = A()) : a_(a) { } T *p_; [[no_unique_address]] A a_; }; int main() { MyType<int> x; MyType<int> y(x); } Example B (ICE): #include <memory> template <class T, class A = std::allocator<T>> struct MyType { MyType(const MyType &other) : a_(std::allocator_traits<A>::select_on_container_copy_construction(other.a_)) { } MyType(const A &a = A()) : a_(std::allocator_traits<A>::select_on_container_copy_construction(a)) { } T *p_; [[no_unique_address]] A a_; }; int main() { MyType<int> x; MyType<int> y(x); } Both cases work correctly if I remove [[no_unique_address], so it seems to be an interaction between [[no_unique_address]] and a_(std::allocator_traits<A>::select_on_container_copy_construction(a)). Here is the complete backtrace for the failing example: g++ -std=c++17 test.cpp -o test during RTL pass: expand test.cpp: In constructor ‘MyType<T, A>::MyType(const A&) [with T = int; A = std::allocator<int>]’: test.cpp:12:74: internal compiler error: in assign_temp, at function.c:982 12 | : a_(std::allocator_traits<A>::select_on_container_copy_construction(a)) { | ^ 0x59a442 assign_temp(tree_node*, int, int) /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/function.c:982 0x7c050f expand_call(tree_node*, rtx_def*, int) /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/calls.c:3459 0x8c4a2d expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool) /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/expr.c:11033 0x8d297b expand_normal /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/expr.h:285 0x8d297b store_field /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/expr.c:7022 0x8cff37 expand_assignment(tree_node*, tree_node*, bool) /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/expr.c:5296 0x7cc3f0 expand_call_stmt /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/cfgexpand.c:2722 0x7cc3f0 expand_gimple_stmt_1 /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/cfgexpand.c:3691 0x7cc3f0 expand_gimple_stmt /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/cfgexpand.c:3850 0x7d1237 expand_gimple_basic_block /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/cfgexpand.c:5890 0x7d35d7 execute /var/tmp/portage/sys-devel/gcc-9.2.0-r2/work/gcc-9.2.0/gcc/cfgexpand.c:6513 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://bugs.gentoo.org/> for instructions.
As a follow-up, it appears that the optimization level is a factor. I only get the ICE in my builds which don't pass a -O flag. Here's a live example that can be experimented with: https://godbolt.org/z/zAEcQd Adding -Og, -O1, -O2, etc... all make it suddenly work.
Most likely a similar issue as PR 93667.
A smaller example: struct S { S(S&&) = delete; }; S foo(); struct A { [[no_unique_address]] S s = foo(); }; A a{}; Version: 11.0.0 20200616 Command line options: -std=c++20 -Wall -Wextra -pedantic Diagnostics: during RTL pass: expand <source>: In function 'void __static_initialization_and_destruction_0(int, int)': <source>:11:5: internal compiler error: in assign_temp, at function.c:984 11 | A a{}; | ^
Same backtrace as bug 90254 but it didn't start with the same revision. This one started with r264813.
*** Bug 95878 has been marked as a duplicate of this bug. ***
Another test: struct istream_iterator { istream_iterator() {} istream_iterator(const istream_iterator&) {} }; istream_iterator next(istream_iterator&& bound) { return static_cast<istream_iterator>(bound); } struct copy_result { [[no_unique_address]] istream_iterator in; }; int main() { copy_result result{next(istream_iterator{})}; }
I don't know if this is the same problem, since the actual `std::istream_iterator<int>` isn't empty, unlike in the other test cases. If the following is a different problem, sorry up front for the noise. https://godbolt.org/z/XAM9o7 This is the actual thing I've come across during a pull request for NanoRange library. DIfferences from the above test cases: - ICE is there even at `-Og`, as well as `-O0` - The bottom example shows that wrapping the call to `fn()` in `std::move()` avoids the ICE. If this is a separate issue and thus noise, I'll open a separate issue.
*** Bug 96408 has been marked as a duplicate of this bug. ***
Another one: struct A { A(const A&) = delete; }; A f(); struct C { [[no_unique_address]] A a; }; C c{f()}; during RTL pass: expand ice.C: In function 'void __static_initialization_and_destruction_0(int, int)': ice.C:10:8: internal compiler error: in assign_temp, at function.c:984 10 | C c{f()}; | ^ 0x6f9772 assign_temp(tree_node*, int, int) /home/jwakely/src/gcc/gcc/gcc/function.c:984 0xb56653 expand_call(tree_node*, rtx_def*, int) /home/jwakely/src/gcc/gcc/gcc/calls.c:3750 0xc87aaa expand_expr_real_1(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool) /home/jwakely/src/gcc/gcc/gcc/expr.c:11240 0xc9a133 expand_expr_real(tree_node*, rtx_def*, machine_mode, expand_modifier, rtx_def**, bool) /home/jwakely/src/gcc/gcc/gcc/expr.c:8474 0xc9a133 expand_normal /home/jwakely/src/gcc/gcc/gcc/expr.h:288 0xc9a133 store_field /home/jwakely/src/gcc/gcc/gcc/expr.c:7213 0xc966d6 expand_assignment(tree_node*, tree_node*, bool) /home/jwakely/src/gcc/gcc/gcc/expr.c:5448 0xb66553 expand_call_stmt /home/jwakely/src/gcc/gcc/gcc/cfgexpand.c:2701 0xb66553 expand_gimple_stmt_1 /home/jwakely/src/gcc/gcc/gcc/cfgexpand.c:3682 0xb66553 expand_gimple_stmt /home/jwakely/src/gcc/gcc/gcc/cfgexpand.c:3847 0xb6bd9a expand_gimple_basic_block /home/jwakely/src/gcc/gcc/gcc/cfgexpand.c:5888 0xb6d846 execute /home/jwakely/src/gcc/gcc/gcc/cfgexpand.c:6572 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions.
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:320054784250e572cb75d6f69ab44b2330d61d8b commit r11-2704-g320054784250e572cb75d6f69ab44b2330d61d8b Author: Jason Merrill <jason@redhat.com> Date: Wed Aug 12 05:45:02 2020 -0400 c++: Copy elision and [[no_unique_address]]. [PR93711] We don't elide a copy from a function returning a class by value into a base because that can overwrite data laid out in the tail padding of the base class; we need to handle [[no_unique_address]] fields the same way, or we ICE when the middle-end wants to create a temporary object of a TYPE_NEEDS_CONSTRUCTING type. This means that we can't always express initialization of a field with INIT_EXPR from a TARGET_EXPR the way we usually do, so I needed to change several places that were assuming that was sufficient. This also fixes 90254, the same problem with C++17 aggregate initialization of a base. gcc/cp/ChangeLog: PR c++/90254 PR c++/93711 * cp-tree.h (unsafe_return_slot_p): Declare. * call.c (is_base_field_ref): Rename to unsafe_return_slot_p. (build_over_call): Check unsafe_return_slot_p. (build_special_member_call): Likewise. * init.c (expand_default_init): Likewise. * typeck2.c (split_nonconstant_init_1): Likewise. gcc/testsuite/ChangeLog: PR c++/90254 PR c++/93711 * g++.dg/cpp1z/aggr-base10.C: New test. * g++.dg/cpp2a/no_unique_address7.C: New test. * g++.dg/cpp2a/no_unique_address7a.C: New test.
Fixed for GCC 11 so far.
The releases/gcc-10 branch has been updated by Jason Merrill <jason@gcc.gnu.org>: https://gcc.gnu.org/g:97014e4ada448aa8978b3cd14ed95e0e56f375d9 commit r10-9168-g97014e4ada448aa8978b3cd14ed95e0e56f375d9 Author: Jason Merrill <jason@redhat.com> Date: Wed Aug 12 05:45:02 2020 -0400 c++: Copy elision and [[no_unique_address]]. [PR93711] We don't elide a copy from a function returning a class by value into a base because that can overwrite data laid out in the tail padding of the base class; we need to handle [[no_unique_address]] fields the same way, or we ICE when the middle-end wants to create a temporary object of a TYPE_NEEDS_CONSTRUCTING type. This means that we can't always express initialization of a field with INIT_EXPR from a TARGET_EXPR the way we usually do, so I needed to change several places that were assuming that was sufficient. This also fixes 90254, the same problem with C++17 aggregate initialization of a base. gcc/cp/ChangeLog: PR c++/90254 PR c++/93711 * cp-tree.h (unsafe_return_slot_p): Declare. * call.c (is_base_field_ref): Rename to unsafe_return_slot_p. (build_over_call): Check unsafe_return_slot_p. (build_special_member_call): Likewise. * init.c (expand_default_init): Likewise. * typeck2.c (split_nonconstant_init_1): Likewise. gcc/testsuite/ChangeLog: PR c++/90254 PR c++/93711 * g++.dg/cpp1z/aggr-base10.C: New test. * g++.dg/cpp2a/no_unique_address7.C: New test. * g++.dg/cpp2a/no_unique_address7a.C: New test.
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
Fixed in 10.2 and later.