Bug 101803 - CTAD fails for nested designated initializers
Summary: CTAD fails for nested designated initializers
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 11.2.1
: P3 normal
Target Milestone: 11.3
Assignee: Patrick Palka
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2021-08-06 13:46 UTC by Hannes Hauswedell
Modified: 2022-06-02 14:10 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2021-08-18 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Hannes Hauswedell 2021-08-06 13:46:09 UTC
See the code below. Two initializing statements fail to build, although they shouldn't influence CTAD of the outer type at all (IMHO).

struct Inner
{
    int i = 0;
};

struct Outer2
{
    Inner s{};
};

template <typename T = int>
struct Outer
{
    Inner s{};
};

int main()
{
    Outer2 o21{ .s = {} };                // works
    Outer2 o22{ .s = Inner{ .i = 1} };    // works
    Outer2 o23{ .s = { .i = 1} };         // works

    Outer2 o24{ .s{} };                   // works
    Outer2 o25{ .s{Inner{ .i = 1} } };    // works
    Outer2 o26{ .s{ .i = 1} };            // works

    Outer o1{ .s = {} };                // works
    Outer o2{ .s = Inner{ .i = 1} };    // works
//    Outer o3{ .s = { .i = 1} };         // does not

    Outer o4{ .s{} };                   // works
    Outer o5{ .s{Inner{ .i = 1} } };    // works
//    Outer o6{ .s{ .i = 1} };            // does not
}
Comment 1 Patrick Palka 2021-08-18 12:53:23 UTC
Fixed on trunk so far by r12-2991 (which incorrectly refers to PR101820 instead of this PR)
Comment 2 GCC Commits 2021-08-19 13:10:35 UTC
The master branch has been updated by Patrick Palka <ppalka@gcc.gnu.org>:

https://gcc.gnu.org/g:4285ca3e1c4a6c9540dcdf1c4a71b99aba9bbfe8

commit r12-3024-g4285ca3e1c4a6c9540dcdf1c4a71b99aba9bbfe8
Author: Patrick Palka <ppalka@redhat.com>
Date:   Thu Aug 19 09:07:02 2021 -0400

    c++: Fix PR number in testcase [PR101803]
    
    Also clarify the description of CONSTRUCTOR_BRACES_ELIDED_P.
    
            PR c++/101803
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (CONSTRUCTOR_IS_PAREN_INIT): Clarify comment.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/cpp2a/class-deduction-aggr12.C: Fix PR number.
Comment 3 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 4 Patrick Palka 2021-10-06 14:17:02 UTC
Fixed for GCC 11.3 and 12.
Comment 5 Hannes Hauswedell 2021-11-26 11:40:34 UTC
Thanks a lot for the fix! Any chance this will make into the 10.x branch?
Comment 6 Hannes Hauswedell 2022-05-31 19:58:18 UTC
Since it seems like 10.4 is around the corner... any chance this will make it?

Thanks a lot!
Comment 7 Patrick Palka 2022-06-02 13:21:26 UTC
(In reply to Hannes Hauswedell from comment #6)
> Since it seems like 10.4 is around the corner... any chance this will make
> it?
> 
> Thanks a lot!

Unfortunately I don't think so :/ the patch doesn't apply cleanly to the 10 branch because it depends on PR93976 / P2082R1.  And we tend to backport non-regression C++20 bugfixes only to the latest release, which in this case was GCC 11.
Comment 8 Hannes Hauswedell 2022-06-02 14:10:14 UTC
OK, thank you anyway!