Bug 98463 - [11 Regression] internal compiler error: in output_constructor_regular_field, at varasm.c:5491 by r11-2720
Summary: [11 Regression] internal compiler error: in output_constructor_regular_field,...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.0
: P1 normal
Target Milestone: 11.0
Assignee: Jason Merrill
URL:
Keywords: ice-on-valid-code
: 96863 98579 (view as bug list)
Depends on:
Blocks: 100489
  Show dependency treegraph
 
Reported: 2020-12-28 15:18 UTC by Romain Geissler
Modified: 2022-05-11 01:57 UTC (History)
8 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2020-12-28 00:00:00


Attachments
gcc11-pr98463.patch (950 bytes, patch)
2021-01-07 13:42 UTC, Jakub Jelinek
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Romain Geissler 2020-12-28 15:18:24 UTC
Hi,

The following C++ code fails to compile with gcc trunk but works on gcc 9 and 10 (tested on compiler explorer):


#include <memory>

struct A
{
    std::unique_ptr<int> _member;
        
    virtual ~A(){}
};

A a;


Compiled without any CXXFLAGS on x64 Linux. Compiler explorer shows:

<source>:10:4: internal compiler error: in output_constructor_regular_field, at varasm.c:5491
   10 | A a;
      |    ^
0x1cba449 internal_error(char const*, ...)
	???:0
0x6b0031 fancy_abort(char const*, int, char const*)
	???:0
0x13ceaf3 assemble_variable(tree_node*, int, int, int)
	???:0
0xb4207f symbol_table::finalize_compilation_unit()
	???:0
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.
Compiler returned: 1

Cheers,
Romain
Comment 1 H.J. Lu 2020-12-28 19:55:54 UTC
This is triggered by r11-2720.
Comment 2 Jonathan Wakely 2020-12-28 20:32:55 UTC
That just exposes a latent compiler bug though.

Slightly reduced:

#include <tuple>

struct empty { };

struct A
{
    std::tuple<int, empty> _member;
        
    virtual ~A(){}
};

A a;
Comment 3 Romain Geissler 2020-12-29 13:56:26 UTC
Hi,

While I initially flagged this as a regression in gcc 11, it's indeed a latent gcc bug which predates gcc 11. What makes it for my specific test case a regression is because now tuple use [[no_unique_address]] which seems to be already identified as creating ICEs in issues #96863 and #97804.

Cheers,
Romain
Comment 4 Jakub Jelinek 2021-01-07 12:22:55 UTC
Reduced testcase:
template <typename T> struct A { constexpr A () : a() {} [[no_unique_address]] T a; };
template <unsigned long, typename...> struct B;
template <unsigned long T, typename U, typename... V>
struct B<T, U, V...> : B<1, V...>, A<U> {};
template <unsigned long T, typename U> struct B<T, U> : A<U> {};
template <typename... h> struct C : B<0, h...> {};
struct D {};
struct E { C<int, D> k; virtual ~E (); } a;
Started to ICE with r9-5710-g7e574f68fa82e7c5f879fd468291ec8b5ebecc83
Comment 5 Jakub Jelinek 2021-01-07 13:08:31 UTC
On #c4, I think the problem is during cxx_eval_store_expression of
((struct A *) this)->a = {};
where this has A * type, but the *valp CONSTRUCTOR we try to get_or_insert_ctor_field it into has type B.  We insert it with FIELD_DECL a which is A's member, but the CONSTRUCTOR handling assumes (rightfully) that the FIELD_DECLs in the CONSTRUCTOR_ELTS indexes are from the type of the CONSTRUCTOR.
Comment 6 Jakub Jelinek 2021-01-07 13:42:24 UTC
Created attachment 49911 [details]
gcc11-pr98463.patch

Untested fix.  Before the PR49290 changes, the empty_base = true; stuff has been
guarded on !addr i.e. !lval, but since
r0-109524-g11f449abc6fc745486699f2f7079497d4c582d40
it doesn't do that anymore.  This patch just restores that behavior.
Comment 7 Jakub Jelinek 2021-01-07 16:58:56 UTC
Unfortunately that patch regresses
+FAIL: g++.dg/cpp0x/constexpr-empty9.C  -std=c++11 (test for excess errors)
+FAIL: g++.dg/cpp0x/constexpr-empty9.C  -std=c++14 (test for excess errors)
+FAIL: g++.dg/cpp0x/constexpr-tuple2.C  -std=c++11 (test for excess errors)
+FAIL: g++.dg/cpp0x/constexpr-tuple2.C  -std=c++14 (test for excess errors)
+FAIL: g++.dg/cpp1y/constexpr-empty2.C  -std=c++14 (test for excess errors)
+FAIL: g++.dg/cpp1y/constexpr-tracking-const24.C  -std=c++14 (test for excess errors)
+FAIL: 20_util/tuple/comparison_operators/overloaded.cc (test for excess errors)

Out of ideas what to do with this.
Comment 8 Jakub Jelinek 2021-01-13 16:29:52 UTC
With the patch for C++14 and older the problem is that the empty base has no FIELD_DECL in the RECORD_TYPE at all, so it then doesn't find anything.
So for the empty_base && lval case it might be better to return some tree that would make it clear to the caller that the code is valid but that it shouldn't really store anything into it.
But still, for C++17 and onwards, we shouldn't be setting empty_base for the lval case if we can find the FIELD_DECL for it (so perhaps for lval move the is_empty_class check to the end) and otherwise figure out what to return.
A freshly created VAR_DECL, or one that is cached (same VAR_DECL for the same type), something else?
Comment 9 Richard Biener 2021-01-19 12:52:20 UTC
*** Bug 98579 has been marked as a duplicate of this bug. ***
Comment 10 Marek Polacek 2021-01-21 21:24:20 UTC
*** Bug 96863 has been marked as a duplicate of this bug. ***
Comment 11 GCC Commits 2021-01-25 15:38:02 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:94ff4c9dd98f39280fba22d1ad0958fb25a5363b

commit r11-6895-g94ff4c9dd98f39280fba22d1ad0958fb25a5363b
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 22 13:17:10 2021 -0500

    c++: [[no_unique_address]] in empty base [PR98463]
    
    In this testcase, cxx_eval_store_expression got confused trying to build up
    CONSTRUCTORs for initializing a subobject because the subobject is a member
    of an empty base.  In C++14 mode and below we don't build FIELD_DECLs for
    empty bases, so the CONSTRUCTOR skipped the empty base, and treated the
    member as a member of the derived class, which breaks.
    
    Fixed by recognizing this situation and giving up on trying to build a
    CONSTRUCTOR for the inner target at that point; since it doesn't have any
    data, we don't need to actually store anything.
    
    gcc/cp/ChangeLog:
    
            PR c++/98463
            * constexpr.c (get_or_insert_ctor_field): Add check.
            (cxx_eval_store_expression): Handle discontinuity of refs.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/98463
            * g++.dg/cpp2a/no_unique_address8.C: New test.
Comment 12 Jason Merrill 2021-01-25 16:12:43 UTC
Fixed.
Comment 13 GCC Commits 2021-01-26 20:01:52 UTC
The master branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:a4dfd0f089af33f2af57bf422f9859405b9b4a16

commit r11-6918-ga4dfd0f089af33f2af57bf422f9859405b9b4a16
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Jan 24 00:55:49 2021 -0500

    c++: constexpr and empty fields [PR97566]
    
    In the discussion of PR98463, Jakub pointed out that in C++17 and up,
    cxx_fold_indirect_ref_1 could use the field we build for an empty base.  I
    tried implementing that, but it broke one of the tuple tests, so I did some
    more digging.
    
    To start with, I generalized the PR98463 patch to handle the case where we
    do have a field, for an empty base or [[no_unique_address]] member.  This is
    enough also for the no-field case because the member of the empty base must
    itself be an empty field; if it weren't, the base would not be empty.
    
    I looked for related PRs and found 97566, which was also fixed by the patch.
    After some poking around to figure out why, I noticed that the testcase had
    been breaking because E, though an empty class, has an ABI nvsize of one
    byte, and we were giving the [[no_unique_address]] FIELD_DECL that
    DECL_SIZE, whereas in build_base_field_1 empty base fields always get
    DECL_SIZE zero, and various places were relying on that to recognize empty
    fields.  So I adjusted both the size and the checking.  When I adjusted
    check_bases I wondered if we were correctly handling bases with only empty
    data members, but it appears we do.
    
    I'm deferring the cxx_fold_indirect_ref_1 change until stage 1, as I don't
    think it actually fixes anything.
    
    gcc/cp/ChangeLog:
    
            PR c++/97566
            PR c++/98463
            * class.c (layout_class_type): An empty field gets size 0.
            (is_empty_field): New.
            (check_bases): Check it.
            * cp-tree.h (is_empty_field): Declare it.
            * constexpr.c (cxx_eval_store_expression): Check it.
            (cx_check_missing_mem_inits): Likewise.
            * init.c (perform_member_init): Likewise.
            * typeck2.c (process_init_constructor_record): Likewise.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/97566
            * g++.dg/cpp2a/no_unique_address10.C: New test.
            * g++.dg/cpp2a/no_unique_address9.C: New test.
Comment 14 GCC Commits 2021-01-29 16:00:50 UTC
The releases/gcc-10 branch has been updated by Jason Merrill <jason@gcc.gnu.org>:

https://gcc.gnu.org/g:2127d2c3ee23bbd03f02d88fd82403408696ee4a

commit r10-9314-g2127d2c3ee23bbd03f02d88fd82403408696ee4a
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Jan 22 13:17:10 2021 -0500

    c++: [[no_unique_address]] in empty base [PR98463]
    
    In this testcase, cxx_eval_store_expression got confused trying to build up
    CONSTRUCTORs for initializing a subobject because the subobject is a member
    of an empty base.  In C++14 mode and below we don't build FIELD_DECLs for
    empty bases, so the CONSTRUCTOR skipped the empty base, and treated the
    member as a member of the derived class, which breaks.
    
    Fixed by recognizing this situation and giving up on trying to build a
    CONSTRUCTOR for the inner target at that point; since it doesn't have any
    data, we don't need to actually store anything.
    
    gcc/cp/ChangeLog:
    
            PR c++/98463
            * constexpr.c (get_or_insert_ctor_field): Add check.
            (cxx_eval_store_expression): Handle discontinuity of refs.
    
    gcc/testsuite/ChangeLog:
    
            PR c++/98463
            * g++.dg/cpp2a/no_unique_address8.C: New test.