Bug 101344 - [11/12 Regression] braced-init-list not supported in an aggregate deduction
Summary: [11/12 Regression] braced-init-list not supported in an aggregate deduction
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.1.0
: P3 normal
Target Milestone: 11.3
Assignee: Patrick Palka
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2021-07-06 16:24 UTC by Fedor Chelnokov
Modified: 2021-10-07 06:55 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work: 10.1.0, 10.2.0, 10.3.0
Known to fail: 11.1.0, 11.2.0, 12.0
Last reconfirmed: 2021-07-12 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Fedor Chelnokov 2021-07-06 16:24:12 UTC
Please consider the program as follows. GCC correctly initializes struct A, but in more simple case of struct B it fails:

```
template<typename T, int N>
struct A { T t[N]; };

template<typename T>
struct B { T t[2]; };

int main()
{
   A a{{1, 2}}; // ok in gcc
   B b{{1, 2}}; // error in gcc (ok in other compilers, e.g. msvc)
   return a.t[0];
}
```

I believe, struct B initialization shall work here same way.
Comment 1 Jonathan Wakely 2021-07-12 11:02:55 UTC
N.B. the code requires -std=gnu++20 to compile.

(In reply to Fedor Chelnokov from comment #0)
>    A a{{1, 2}}; // ok in gcc
>    B b{{1, 2}}; // error in gcc (ok in other compilers, e.g. msvc)

FWIW MSVC seems to be the only compiler that accepts it. Clang and Intel do not accept either line, due to incomplete C++20 support.
Comment 2 Patrick Palka 2021-08-12 15:20:58 UTC
Another rejects-valid example (I think):

template<class T=void>
struct C { int m; int t[2]; };

C b{1, {2, 3}};

The relevant wording seems to be https://eel.is/c++draft/over.match.class.deduct#1.5.  Rather than only "considering" brace elision for int[2] (and other non-dependent aggregate type), we seem to require it.
Comment 3 Patrick Palka 2021-08-12 15:27:30 UTC
We started rejecting the comment #2 example after r11-1615
Comment 4 GCC Commits 2021-08-18 12:39:27 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

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

commit r12-2991-gbe4a4fb516688d7cfe28a80a4aa333f4ecf0b518
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Aug 18 08:37:45 2021 -0400

    c++: aggregate CTAD and brace elision [PR101344]
    
    Here the problem is ultimately that collect_ctor_idx_types always
    recurses into an eligible sub-CONSTRUCTOR regardless of whether the
    corresponding pair of braces was elided in the original initializer.
    This causes us to reject some completely-braced forms of aggregate
    CTAD as in the first testcase below, because collect_ctor_idx_types
    effectively assumes that the original initializer is always minimally
    braced (and so the aggregate deduction candidate is given a function
    type that's incompatible with the original completely-braced initializer).
    
    In order to fix this, collect_ctor_idx_types needs to somehow know the
    shape of the original initializer when iterating over the reshaped
    initializer.  To that end this patch makes reshape_init flag sub-ctors
    that were built to undo brace elision in the original ctor, so that
    collect_ctor_idx_types that determine whether to recurse into a sub-ctor
    by simply inspecting this flag.
    
    This happens to also fix PR101820, which is about aggregate CTAD using
    designated initializers, for much the same reasons.
    
    A curious case is the "intermediately-braced" initialization of 'e3'
    (which we reject) in the first testcase below.  It seems to me we're
    behaving as specified here (according to [over.match.class.deduct]/1)
    because the initializer element x_1={1, 2, 3, 4} corresponds to the
    subobject e_1=E::t, hence the type T_1 of the first function parameter
    of the aggregate deduction candidate is T(&&)[2][2], but T can't be
    deduced from x_1 using this parameter type (as opposed to say T(&&)[4]).
    
            PR c++/101344
            PR c++/101820
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define.
            * decl.c (reshape_init_r): Set it.
            * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR
            iff CONSTRUCTOR_BRACES_ELIDED_P.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/class-deduction-aggr11.C: New test.
            * g++.dg/cpp2a/class-deduction-aggr12.C: New test.
Comment 5 Patrick Palka 2021-08-18 12:51:19 UTC
Whoops, wrong PR number.. the above commit should refer to PR101803 not PR101820.  I'll correct this tomorrow, after the ChangeLog entry is generated
Comment 6 GCC Commits 2021-10-06 14:15:20 UTC
The releases/gcc-11 branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

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

commit r11-9079-gdc867191914eff2993312fc25c48db4b7c6289e9
Author: Patrick Palka <ppalka@redhat.com>
Date:   Wed Aug 18 08:37:45 2021 -0400

    c++: aggregate CTAD and brace elision [PR101344]
    
    Here the problem is ultimately that collect_ctor_idx_types always
    recurses into an eligible sub-CONSTRUCTOR regardless of whether the
    corresponding pair of braces was elided in the original initializer.
    This causes us to reject some completely-braced forms of aggregate
    CTAD as in the first testcase below, because collect_ctor_idx_types
    effectively assumes that the original initializer is always minimally
    braced (and so the aggregate deduction candidate is given a function
    type that's incompatible with the original completely-braced initializer).
    
    In order to fix this, collect_ctor_idx_types needs to somehow know the
    shape of the original initializer when iterating over the reshaped
    initializer.  To that end this patch makes reshape_init flag sub-ctors
    that were built to undo brace elision in the original ctor, so that
    collect_ctor_idx_types that determine whether to recurse into a sub-ctor
    by simply inspecting this flag.
    
    This happens to also fix PR101820, which is about aggregate CTAD using
    designated initializers, for much the same reasons.
    
    A curious case is the "intermediately-braced" initialization of 'e3'
    (which we reject) in the first testcase below.  It seems to me we're
    behaving as specified here (according to [over.match.class.deduct]/1)
    because the initializer element x_1={1, 2, 3, 4} corresponds to the
    subobject e_1=E::t, hence the type T_1 of the first function parameter
    of the aggregate deduction candidate is T(&&)[2][2], but T can't be
    deduced from x_1 using this parameter type (as opposed to say T(&&)[4]).
    
            PR c++/101344
            PR c++/101803
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (CONSTRUCTOR_BRACES_ELIDED_P): Define.
            * decl.c (reshape_init_r): Set it.
            * pt.c (collect_ctor_idx_types): Recurse into a sub-CONSTRUCTOR
            iff CONSTRUCTOR_BRACES_ELIDED_P.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/class-deduction-aggr11.C: New test.
            * g++.dg/cpp2a/class-deduction-aggr12.C: New test.
    
    (cherry picked from commit be4a4fb516688d7cfe28a80a4aa333f4ecf0b518)
Comment 7 Patrick Palka 2021-10-06 14:18:25 UTC
Fixed for GCC 11.3 and 12.
Comment 8 Fedor Chelnokov 2021-10-07 06:55:59 UTC
Thanks!

Related discussion: https://stackoverflow.com/q/67280884/7325599