Hi, thanks for the patch!

On Fri, 15 Aug 2025, seha-bot wrote:

> From: Nedim Šehić <nedimsehi...@gmail.com>
> 
> Regtested on x86_64-pc-linux-gnu.
> 
> This patch fixes deduction for member array types from parenthesized
> initializers which use braces and string literals.
> 
>         PR c++/121518
> 
> gcc/cp/ChangeLog:
> 
>         * pt.cc (maybe_aggr_guide): Add deduction for brace and string
>           literal initializer cases.
> 
> gcc/testsuite/ChangeLog:
> 
>         * g++.dg/cpp2a/class-deduction-aggr17.C: New test.
> 
> Co-Authored-By: Nathaniel Shead <nathanielosh...@gmail.com>
> Signed-off-by: Nedim Šehić <nedimsehi...@gmail.com>
> ---
>  gcc/cp/pt.cc                                  | 22 +++--
>  .../g++.dg/cpp2a/class-deduction-aggr17.C     | 88 +++++++++++++++++++
>  2 files changed, 105 insertions(+), 5 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr17.C
> 
> diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> index b6b13edd03f..35c3ce517e8 100644
> --- a/gcc/cp/pt.cc
> +++ b/gcc/cp/pt.cc
> @@ -31116,22 +31116,34 @@ maybe_aggr_guide (tree tmpl, tree init, 
> vec<tree,va_gc> *args)
>      }
>    else if (TREE_CODE (init) == TREE_LIST)
>      {
> -      int len = list_length (init);
> +      tree elt = init;
>        for (tree binfo : BINFO_BASE_BINFOS (TYPE_BINFO (template_type)))
>       {
> -       if (!len)
> +       if (!elt)
>           break;
>         parms = tree_cons (NULL_TREE, BINFO_TYPE (binfo), parms);
> -       --len;
> +       elt = TREE_CHAIN (elt);
>       }
>        for (tree field = TYPE_FIELDS (template_type);
> -        len;
> -        --len, field = DECL_CHAIN (field))
> +     elt;
> +     elt = TREE_CHAIN (elt), field = DECL_CHAIN (field))

The identation seems off in this hunk.

>       {
>         field = next_aggregate_field (field);
>         if (!field)
>           return NULL_TREE;
>         tree ftype = finish_decltype_type (field, true, complain);
> +    tree arg = tree_strip_any_location_wrapper (TREE_VALUE (elt));
> +    if (TREE_CODE (ftype) == ARRAY_TYPE)
> +      {
> +        if (BRACE_ENCLOSED_INITIALIZER_P (arg))
> +          ftype = cp_build_reference_type (ftype, true);
> +        else if (TREE_CODE (arg) == STRING_CST)
> +          {
> +            ftype = cp_build_qualified_type
> +              (ftype, cp_type_quals (ftype) | TYPE_QUAL_CONST);
> +            ftype = cp_build_reference_type (ftype, false);
> +          }
> +      }

Indentation seems off here too.  And I think we could sink the variable
'arg' into the if.

Besides that, LGTM, we have similar logic in collect_ctor_idx_types
(for aggregate CTAD from {} rather than ()).  I guess duplicating it
isn't ideal but I don't mind too much.  Jason, what do you think?

>         parms = tree_cons (NULL_TREE, ftype, parms);
>       }
>      }
> diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr17.C 
> b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr17.C
> new file mode 100644
> index 00000000000..9fa63369426
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-aggr17.C
> @@ -0,0 +1,88 @@
> +// PR c++/121518
> +// { dg-do compile { target c++20 } }
> +
> +#include <cstddef>
> +#include <utility>
> +
> +template <std::size_t N>
> +struct Str {
> +    char x[N]{};
> +};
> +
> +struct MovableType {
> +    MovableType() = default;
> +    MovableType(MovableType const&) = delete;
> +    MovableType(MovableType&&) = default;
> +};
> +
> +struct ImmovableType {
> +    ImmovableType() = default;
> +    ImmovableType(ImmovableType&&) = delete;
> +};
> +
> +template <typename T, std::size_t N>
> +struct Deduct {
> +    T x[N]{};
> +};
> +
> +template<class, class> struct same;
> +template<class T> struct same<T, T> {};
> +
> +Str s0("a");
> +same<decltype(s0), Str<2>> c0;
> +Str s1{"a"};
> +same<decltype(s1), Str<2>> c1;
> +Str s2 = {"a"};
> +same<decltype(s2), Str<2>> c2;
> +
> +Str s3({'a', '\0'});
> +same<decltype(s3), Str<2>> c3;
> +Str s4{{'a', '\0'}};
> +same<decltype(s4), Str<2>> c4;
> +Str s5 = {{'a', '\0'}};
> +same<decltype(s5), Str<2>> c5;
> +
> +Deduct ds0("a");
> +same<decltype(ds0), Deduct<char, 2>> c15;
> +Deduct ds1{"a"};
> +same<decltype(ds1), Deduct<char, 2>> c16;
> +Deduct ds2 = {"a"};
> +same<decltype(ds2), Deduct<char, 2>> c17;
> +
> +Deduct ds3({'a', '\0'});
> +same<decltype(ds3), Deduct<char, 2>> c18;
> +Deduct ds4{{'a', '\0'}};
> +same<decltype(ds4), Deduct<char, 2>> c19;
> +Deduct ds5 = {{'a', '\0'}};
> +same<decltype(ds5), Deduct<char, 2>> c20;
> +
> +MovableType mt;
> +Deduct dm0({MovableType{}});
> +same<decltype(dm0), Deduct<MovableType, 1>> c21;
> +Deduct dm1({MovableType{}, std::move(mt)});
> +same<decltype(dm1), Deduct<MovableType, 2>> c22;
> +
> +Deduct dm2{{MovableType{}}};
> +same<decltype(dm2), Deduct<MovableType, 1>> c23;
> +Deduct dm3{{MovableType{}, std::move(mt)}};
> +same<decltype(dm3), Deduct<MovableType, 2>> c24;
> +
> +Deduct dm4 = {{MovableType{}}};
> +same<decltype(dm4), Deduct<MovableType, 1>> c25;
> +Deduct dm5 = {{MovableType{}, std::move(mt)}};
> +same<decltype(dm5), Deduct<MovableType, 2>> c26;
> +
> +Deduct dm6({MovableType{}, mt}); // { dg-error "use of deleted function" }
> +
> +ImmovableType it;
> +Deduct di0({ImmovableType{}});
> +same<decltype(di0), Deduct<ImmovableType, 1>> c27;
> +Deduct di1({ImmovableType{}, std::move(it)});  // { dg-error "use of deleted 
> function" }
> +
> +Deduct di2{{ImmovableType{}}};
> +same<decltype(di2), Deduct<ImmovableType, 1>> c28;
> +Deduct di3{{ImmovableType{}, std::move(it)}};  // { dg-error "use of deleted 
> function" }
> +
> +Deduct di4 = {{ImmovableType{}}};
> +same<decltype(di4), Deduct<ImmovableType, 1>> c29;
> +Deduct di5 = {{ImmovableType{}, std::move(it)}};  // { dg-error "use of 
> deleted function" }
> -- 
> 2.50.1
> 
> 

Reply via email to