On Wed, Jun 10, 2026 at 06:06:23PM -0400, Jason Merrill wrote:
> On 6/10/26 3:48 PM, Marek Polacek wrote:
> > On Tue, Jun 09, 2026 at 04:22:38PM -0400, Jason Merrill wrote:
> > > On 6/4/26 6:26 PM, Marek Polacek wrote:
> > > > On Thu, Jun 04, 2026 at 05:20:30PM -0400, Jason Merrill wrote:
> > > > > On 6/4/26 3:39 PM, Marek Polacek wrote:
> > > > > > On Wed, Jun 03, 2026 at 03:41:56PM -0400, Jason Merrill wrote:
> > > > > > > On 6/2/26 5:59 PM, Marek Polacek wrote:
> > > > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for 
> > > > > > > > trunk/branches?
> > > > > > > > 
> > > > > > > > -- >8 --
> > > > > > > > Here we crash because a TARGET_EXPR gets into tsubst_expr with 
> > > > > > > > something
> > > > > > > > like:
> > > > > > > > 
> > > > > > > >       template<typename>
> > > > > > > >       constexpr static A a = (A{}, A{});
> > > > > > > > 
> > > > > > > > Pre r14-4796, when we had tsubst_copy, we didn't crash because 
> > > > > > > > we had
> > > > > > > > an early exit when substituting with args=NULL_TREE.  
> > > > > > > > tsubst_expr
> > > > > > > > deliberately doesn't have that early exit.
> > > > > > > > 
> > > > > > > > Note that
> > > > > > > > 
> > > > > > > >       template<typename>
> > > > > > > >       constexpr static A a = A{};
> > > > > > > > 
> > > > > > > > works because expand_aggr_init_1 sees a COMPOUND_LITERAL_P and 
> > > > > > > > does the
> > > > > > > > early exit without calling expand_default_init.  But with a 
> > > > > > > > COMPOUND_EXPR
> > > > > > > > we don't take that path.
> > > > > > > > 
> > > > > > > > The TARGET_EXPR is created via check_initializer -> 
> > > > > > > > build_aggr_init_full_exprs
> > > > > > > > -> build_aggr_init -> expand_aggr_init_1 -> expand_default_init 
> > > > > > > > -> ocp_convert
> > > > > > > > -> build_cplus_new -> build_target_expr.  I tried adjusting the 
> > > > > > > > big
> > > > > > > > and ugly check in check_initializer before 
> > > > > > > > build_aggr_init_full_exprs
> > > > > > > > but that didn't work out.  I also tried avoiding the call to 
> > > > > > > > ocp_convert
> > > > > > > > but that broke some reflection tests.  But avoiding the call to
> > > > > > > > build_cplus_new seems to work.
> > > > > > > > 
> > > > > > > >         PR c++/125539
> > > > > > > > 
> > > > > > > > gcc/cp/ChangeLog:
> > > > > > > > 
> > > > > > > >         * cvt.cc (ocp_convert): Don't call build_cplus_new in a
> > > > > > > >         template.
> > > > > > > 
> > > > > > > I notice that build_aggr_init_expr already shortcuts
> > > > > > > processing_template_decl.  What if we do that in build_cplus_new 
> > > > > > > as well, if
> > > > > > > init has the right type?
> > > > > > 
> > > > > > I think that looks better, and is a more general fix.
> > > > > > 
> > > > > > dg.exp passed; ok for trunk/branches if the rest of the testing 
> > > > > > passes too?
> > > > > > 
> > > > > > -- >8 --
> > > > > > Here we crash because a TARGET_EXPR gets into tsubst_expr with 
> > > > > > something
> > > > > > like:
> > > > > > 
> > > > > >      template<typename>
> > > > > >      constexpr static A a = (A{}, A{});
> > > > > > 
> > > > > > Pre r14-4796, when we had tsubst_copy, we didn't crash because we 
> > > > > > had
> > > > > > an early exit when substituting with args=NULL_TREE.  tsubst_expr
> > > > > > deliberately doesn't have that early exit.
> > > > > > 
> > > > > > Note that
> > > > > > 
> > > > > >      template<typename>
> > > > > >      constexpr static A a = A{};
> > > > > > 
> > > > > > works because expand_aggr_init_1 sees a COMPOUND_LITERAL_P and does 
> > > > > > the
> > > > > > early exit without calling expand_default_init.  But with a 
> > > > > > COMPOUND_EXPR
> > > > > > we don't take that path.
> > > > > > 
> > > > > > The TARGET_EXPR is created via check_initializer -> 
> > > > > > build_aggr_init_full_exprs
> > > > > > -> build_aggr_init -> expand_aggr_init_1 -> expand_default_init -> 
> > > > > > ocp_convert
> > > > > > -> build_cplus_new -> build_target_expr.  I tried adjusting the big
> > > > > > and ugly check in check_initializer before 
> > > > > > build_aggr_init_full_exprs
> > > > > > but that didn't work out.  I also tried avoiding the call to 
> > > > > > ocp_convert
> > > > > > but that broke some reflection tests.
> > > > > > 
> > > > > > We can fix this by returning early in build_cplus_new in a template,
> > > > > > like in build_aggr_init_expr.
> > > > > > 
> > > > > >     PR c++/125539
> > > > > > 
> > > > > > gcc/cp/ChangeLog:
> > > > > > 
> > > > > >     * tree.cc (build_cplus_new): In a template, return before 
> > > > > > creating
> > > > > >     a TARGET_EXPR.
> > > > > > 
> > > > > > gcc/testsuite/ChangeLog:
> > > > > > 
> > > > > >     * g++.dg/cpp1y/var-templ89.C: New test.
> > > > > > ---
> > > > > >     gcc/cp/tree.cc                           |  5 ++++
> > > > > >     gcc/testsuite/g++.dg/cpp1y/var-templ89.C | 32 
> > > > > > ++++++++++++++++++++++++
> > > > > >     2 files changed, 37 insertions(+)
> > > > > >     create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ89.C
> > > > > > 
> > > > > > diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
> > > > > > index 360eae87698..df9dd562314 100644
> > > > > > --- a/gcc/cp/tree.cc
> > > > > > +++ b/gcc/cp/tree.cc
> > > > > > @@ -838,6 +838,11 @@ build_cplus_new (tree type, tree init, 
> > > > > > tsubst_flags_t complain)
> > > > > >       if (abstract_virtuals_error (NULL_TREE, type, complain))
> > > > > >         return error_mark_node;
> > > > > > +  /* As in build_aggr_init_expr.  We don't want to create a 
> > > > > > TARGET_EXPR
> > > > > > +     in a template.  */
> > > > > > +  if (processing_template_decl)
> > > > > > +    return rval;
> > > > > 
> > > > > I mentioned "if init has the right type"; we need to check that so we 
> > > > > don't
> > > > > just return a void constructor call.
> > > > 
> > > > Oop, now I see what you meant, sorry.
> > > > 
> > > > If I check
> > > > 
> > > >     if (processing_template_decl
> > > >         && same_type_ignoring_top_level_qualifiers_p (type, TREE_TYPE 
> > > > (init)))
> > > >       return rval;
> > > > 
> > > > then we crash on var-templ89.C with -std=c++14 because we don't
> > > > elide the copy, so have a ctor call, so the types don't match, so
> > > > we create a TARGET_EXPR.
> > > 
> > > Ah, well.  So I guess shortcutting the template case in ocp_convert, but
> > > again returning the constructor call is wrong; perhaps we should take the
> > > earlier perform_implicit_conversion route in a template?
> > 
> > Thanks.  Maybe something like this, then?
> > 
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?
> > 
> > -- >8 --
> > Here we crash because a TARGET_EXPR gets into tsubst_expr with something
> > like:
> > 
> >    template<typename>
> >    constexpr static A a = (A{}, A{});
> > 
> > Pre r14-4796, when we had tsubst_copy, we didn't crash because we had
> > an early exit when substituting with args=NULL_TREE.  tsubst_expr
> > deliberately doesn't have that early exit.
> > 
> > Note that
> > 
> >    template<typename>
> >    constexpr static A a = A{};
> > 
> > works because expand_aggr_init_1 sees a COMPOUND_LITERAL_P and does the
> > early exit without calling expand_default_init.  But with a COMPOUND_EXPR
> > we don't take that path.
> > 
> > The TARGET_EXPR is created via check_initializer -> 
> > build_aggr_init_full_exprs
> > -> build_aggr_init -> expand_aggr_init_1 -> expand_default_init -> 
> > ocp_convert
> > -> build_cplus_new -> build_target_expr.  I tried adjusting the big
> > and ugly check in check_initializer before build_aggr_init_full_exprs
> > but that didn't work out.  I also tried avoiding the call to ocp_convert
> > but that broke some reflection tests.
> > 
> > We can fix this by calling perform_implicit_conversion in a template to
> > create an IMPLICIT_CONV_EXPR, then build_cplus_new won't create a 
> > TARGET_EXPR.
> > 
> >     PR c++/125539
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * cvt.cc (ocp_convert): In a template, always call
> >     perform_implicit_conversion.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/cpp1y/var-templ89.C: New test.
> > ---
> >   gcc/cp/cvt.cc                            |  5 +++-
> >   gcc/testsuite/g++.dg/cpp1y/var-templ89.C | 32 ++++++++++++++++++++++++
> >   2 files changed, 36 insertions(+), 1 deletion(-)
> >   create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ89.C
> > 
> > diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
> > index b1176317d99..d5a64e098d2 100644
> > --- a/gcc/cp/cvt.cc
> > +++ b/gcc/cp/cvt.cc
> > @@ -968,7 +968,10 @@ ocp_convert (tree type, tree expr, int convtype, int 
> > flags,
> >         if (abstract_virtuals_error (NULL_TREE, type, complain))
> >     return error_mark_node;
> > -      if (BRACE_ENCLOSED_INITIALIZER_P (ctor))
> > +      if (BRACE_ENCLOSED_INITIALIZER_P (ctor)
> > +     /* We don't want to create a TARGET_EXPR in a template by the
> > +        build_cplus_new below.  */
> > +     || processing_template_decl)
> >     ctor = perform_implicit_conversion (type, ctor, complain);
> 
> I think this should be perform_implicit_conversion_flags now.

Ok, though nothing triggers the case where flags != LOOKUP_IMPLICIT.

> With this patch do we still need this in check_initializer?
> 
> > =>            if (processing_template_decl && TREE_CODE (rhs) == 
> > TARGET_EXPR)
> >                 /* Avoid leaking TARGET_EXPR into template trees.  */
> >                 rhs = build_implicit_conv_flags (type, init, flags);

Nothing breaks if I remove the whole thing.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/branches?

-- >8 --
Here we crash because a TARGET_EXPR gets into tsubst_expr with something
like:

  template<typename>
  constexpr static A a = (A{}, A{});

Pre r14-4796, when we had tsubst_copy, we didn't crash because we had
an early exit when substituting with args=NULL_TREE.  tsubst_expr
deliberately doesn't have that early exit.

Note that

  template<typename>
  constexpr static A a = A{};

works because expand_aggr_init_1 sees a COMPOUND_LITERAL_P and does the
early exit without calling expand_default_init.  But with a COMPOUND_EXPR
we don't take that path.

The TARGET_EXPR is created via check_initializer -> build_aggr_init_full_exprs
-> build_aggr_init -> expand_aggr_init_1 -> expand_default_init -> ocp_convert
-> build_cplus_new -> build_target_expr.  I tried adjusting the big
and ugly check in check_initializer before build_aggr_init_full_exprs
but that didn't work out.  I also tried avoiding the call to ocp_convert
but that broke some reflection tests.

We can fix this by calling perform_implicit_conversion in a template to
create an IMPLICIT_CONV_EXPR, then build_cplus_new won't create a TARGET_EXPR.

        PR c++/125539

gcc/cp/ChangeLog:

        * cvt.cc (ocp_convert): In a template, always call
        perform_implicit_conversion.  Pass flags to
        perform_implicit_conversion_flags.
        * decl.cc (check_initializer): Remove a call to
        build_implicit_conv_flags.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp1y/var-templ89.C: New test.
---
 gcc/cp/cvt.cc                            |  7 ++++--
 gcc/cp/decl.cc                           |  7 +-----
 gcc/testsuite/g++.dg/cpp1y/var-templ89.C | 32 ++++++++++++++++++++++++
 3 files changed, 38 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/var-templ89.C

diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc
index b1176317d99..b18f66e582f 100644
--- a/gcc/cp/cvt.cc
+++ b/gcc/cp/cvt.cc
@@ -968,8 +968,11 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
       if (abstract_virtuals_error (NULL_TREE, type, complain))
        return error_mark_node;
 
-      if (BRACE_ENCLOSED_INITIALIZER_P (ctor))
-       ctor = perform_implicit_conversion (type, ctor, complain);
+      if (BRACE_ENCLOSED_INITIALIZER_P (ctor)
+         /* We don't want to create a TARGET_EXPR in a template by the
+            build_cplus_new below.  */
+         || processing_template_decl)
+       ctor = perform_implicit_conversion_flags (type, ctor, complain, flags);
       else if ((flags & LOOKUP_ONLYCONVERTING)
               && ! (CLASS_TYPE_P (dtype) && DERIVED_FROM_P (type, dtype)))
        /* For copy-initialization, first we create a temp of the proper type
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index cba85c959ff..23f23b39544 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -8625,12 +8625,7 @@ check_initializer (tree decl, tree init, int flags, 
vec<tree, va_gc> **cleanups)
              /* In C++20, the call to build_aggr_init could have created
                 an INIT_EXPR with a CONSTRUCTOR as the RHS to handle
                 A(1, 2).  */
-             tree rhs = TREE_OPERAND (init_code, 1);
-             if (processing_template_decl && TREE_CODE (rhs) == TARGET_EXPR)
-               /* Avoid leaking TARGET_EXPR into template trees.  */
-               rhs = build_implicit_conv_flags (type, init, flags);
-             init = rhs;
-
+             init = TREE_OPERAND (init_code, 1);
              init_code = NULL_TREE;
              /* Don't call digest_init; it's unnecessary and will complain
                 about aggregate initialization of non-aggregate classes.  */
diff --git a/gcc/testsuite/g++.dg/cpp1y/var-templ89.C 
b/gcc/testsuite/g++.dg/cpp1y/var-templ89.C
new file mode 100644
index 00000000000..5f98a95580c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/var-templ89.C
@@ -0,0 +1,32 @@
+// PR c++/125539
+// { dg-do compile { target c++14 } }
+
+struct A {};
+struct B { int i; };
+constexpr void foo () {}
+
+template<typename T>
+constexpr static A a1 = (foo (), A {});
+template<typename T>
+constexpr static A a2 = (A{}, A{});
+template<typename T>
+constexpr static A a3 = A{};
+template<typename T>
+constexpr static A a4 = {};
+template<typename T>
+constexpr static A a5{};
+template<typename T>
+constexpr static A a6 = (A{}, A{}, A{}, A{}, A{}, A{}, A{});
+template<int N>
+constexpr static B b1 = B{N};
+template<int N>
+constexpr static B b2 = (B{N}, B{N});
+
+template const A a1<int>;
+template const A a2<int>;
+template const A a3<int>;
+template const A a4<int>;
+template const A a5<int>;
+template const A a6<int>;
+template const B b1<42>;
+template const B b2<42>;

base-commit: cd52e71e8aea258342deca45868bf2529d4fdd76
-- 
2.54.0

Reply via email to