On Fri, 15 May 2026, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?
> 
> -- >8 --
> When looking into 125315 I came up with another test that crashes
> due to an empty object.  It still crashes even after Jason's patch.
> 
> Here we have a subobject nested in an empty object:
> 
>   {.w = {.v = TARGET_EXPR <f(s)>}}
> 
> w's type is W, an empty union due to [[no_unique_address]], so
> init_subob_ctx clears the ctor, but then we recurse to
> 
>   {.v = TARGET_EXPR <f(s)>}
> 
> with a null ctx->ctor so the call to get_or_insert_ctor_field in
> cxx_eval_bare_aggregate crashes.  This fixes the crash similarly
> to c++/125315.
> 
> no_unique_address18.C worked fine even before this patch because
> there we don't have an empty object.  But let's test it also.
> 
>       PR c++/125336
> 
> gcc/cp/ChangeLog:
> 
>       * constexpr.cc (cxx_eval_bare_aggregate): Don't call
>       get_or_insert_ctor_field when there is no CONSTRUCTOR.  Assert
>       is_empty_class.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/cpp2a/no_unique_address17.C: New test.
>       * g++.dg/cpp2a/no_unique_address18.C: New test.
> ---
>  gcc/cp/constexpr.cc                              |  8 ++++++--
>  gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C | 12 ++++++++++++
>  gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C | 12 ++++++++++++
>  3 files changed, 30 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
>  create mode 100644 gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C
> 
> diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
> index 1fc8a56503c..84896170d05 100644
> --- a/gcc/cp/constexpr.cc
> +++ b/gcc/cp/constexpr.cc
> @@ -6841,7 +6841,11 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, 
> tree t,
>        /* Like in cxx_eval_store_expression, omit entries for empty fields.  
> */
>        bool no_slot = new_ctx.ctor == NULL_TREE;
>        int pos_hint = -1;
> -      if (new_ctx.ctor != ctx->ctor && !no_slot)
> +      if (!ctx->ctor)
> +     /* The enclosing object could be an empty subobject so we have no
> +        CONSTRUCTOR (c++/125336).  */
> +     gcc_checking_assert (is_empty_class (type));
> +      else if (new_ctx.ctor != ctx->ctor && !no_slot)
>       {
>         /* If we built a new CONSTRUCTOR, attach it now so that other
>            initializers can refer to it.  */
> @@ -6892,7 +6896,7 @@ cxx_eval_bare_aggregate (const constexpr_ctx *ctx, tree 
> t,
>         gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (index))));
>         changed = true;
>       }
> -      else
> +      else if (ctx->ctor)
>       {
>         if (TREE_CODE (type) == UNION_TYPE
>             && (*p)->last().index != index)
> diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C 
> b/gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
> new file mode 100644
> index 00000000000..11099698a9b
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address17.C
> @@ -0,0 +1,12 @@
> +// PR c++/125336
> +// { dg-do compile { target c++20 } }
> +// { dg-prune-output "used but never defined" }

The "used but never defined" warning implies the testcase is UB right?
Would be nice to have a valid testcase that triggers this bug.

> +
> +struct S{ };
> +constexpr S& f (S&);
> +union W {
> +  [[no_unique_address]] S v;
> +};
> +struct R { W w; };
> +S s;
> +auto x = R{{ f(s) }};
> diff --git a/gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C 
> b/gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C
> new file mode 100644
> index 00000000000..bea8a65b8a0
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp2a/no_unique_address18.C
> @@ -0,0 +1,12 @@
> +// PR c++/125336
> +// { dg-do compile { target c++20 } }
> +// { dg-prune-output "used but never defined" }
> +
> +struct S { int i; };
> +constexpr S& f (S&);
> +union W {
> +  [[no_unique_address]] S v;
> +};
> +struct R { W w; };
> +S s;
> +auto x = R{{ f(s) }};
> 
> base-commit: f108e23d2bff50d0ee8cf0d25a08be5432b702b6
> -- 
> 2.54.0
> 
> 

Reply via email to