On Thu, May 07, 2026 at 02:31:52PM -0400, Jason Merrill wrote:
> On 5/7/26 1:36 PM, Marek Polacek wrote:
> > On Wed, May 06, 2026 at 04:47:09PM -0400, Jason Merrill wrote:
> > > On 4/22/26 1:36 PM, Marek Polacek wrote:
> > > > On Tue, Apr 21, 2026 at 05:20:02PM -0400, Jason Merrill wrote:
> > > > > On 4/21/26 4:21 PM, Marek Polacek wrote:
> > > > > > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > > > > > 
> > > > > > -- >8 --
> > > > > > wrapup_namespace_globals gives errors for code like
> > > > > > 
> > > > > >      extern inline int i;
> > > > > >      int &r = i; // odr-used inline variable is not defined
> > > > > > 
> > > > > > but because we mark consteval-only vars DECL_EXTERNAL, we also 
> > > > > > wrongly
> > > > > > emit the error for:
> > > > > > 
> > > > > >      inline constexpr info value{};
> > > > > >      static_assert(value == info{});
> > > > > > 
> > > > > > where value clearly is defined.  ISTM that we should check 
> > > > > > !consteval_only_p
> > > > > > before giving this error because the test where this could trigger:
> > > > > > 
> > > > > >      extern constexpr inline info x;
> > > > > > 
> > > > > > is already ill-formed ("declaration of 'constexpr' variable 'x' is 
> > > > > > not
> > > > > > a definition").
> > > > > > 
> > > > > >     PR c++/124770
> > > > > > 
> > > > > > gcc/cp/ChangeLog:
> > > > > > 
> > > > > >     * decl.cc (wrapup_namespace_globals): Don't give the odr-used
> > > > > >     inline variable error for consteval-only variables.
> > > > > > 
> > > > > > gcc/testsuite/ChangeLog:
> > > > > > 
> > > > > >     * g++.dg/reflect/init18.C: New test.
> > > > > > ---
> > > > > >     gcc/cp/decl.cc                        |  6 +++++-
> > > > > >     gcc/testsuite/g++.dg/reflect/init18.C | 14 ++++++++++++++
> > > > > >     2 files changed, 19 insertions(+), 1 deletion(-)
> > > > > >     create mode 100644 gcc/testsuite/g++.dg/reflect/init18.C
> > > > > > 
> > > > > > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > > > > > index 679a8007ca6..7837e322d17 100644
> > > > > > --- a/gcc/cp/decl.cc
> > > > > > +++ b/gcc/cp/decl.cc
> > > > > > @@ -1024,7 +1024,11 @@ wrapup_namespace_globals ()
> > > > > >               if (VAR_P (decl)
> > > > > >                   && DECL_EXTERNAL (decl)
> > > > > >                   && DECL_INLINE_VAR_P (decl)
> > > > > > -         && DECL_ODR_USED (decl))
> > > > > > +         && DECL_ODR_USED (decl)
> > > > > > +         /* We mark consteval-only vars extern, but they also have 
> > > > > > to be
> > > > > > +            declared constexpr and "extern constexpr inline info 
> > > > > > x;" is
> > > > > > +            ill-formed.  */
> > > > > > +         && !consteval_only_p (decl))
> > > > > 
> > > > > Would it work to check DECL_THIS_EXTERN instead, so we're complaining 
> > > > > about
> > > > > an extern declaration rather than just based on the compiler deciding 
> > > > > not to
> > > > > emit?
> > > > 
> > > > Sadly, no, we'd give the error for
> > > > 
> > > >     extern constexpr inline info v2{};
> > > >     static_assert(v2 == info{});
> > > > 
> > > > where the extern is I think redundant due to [basic.link]/3.2.3.
> > > > EDG and clang++ accept that code too.
> > > 
> > > Ah, true, but DECL_THIS_EXTERN && !DECL_INITIAL ought to work?
> > 
> > It does!  v2 here.
> > > (decl_defined_p could also use refinement)
> > 
> > Like this?  (I can send it separately.)
> > 
> > --- a/gcc/cp/decl2.cc
> > +++ b/gcc/cp/decl2.cc
> > @@ -5324,7 +5324,9 @@ decl_defined_p (tree decl)
> >     else
> >       {
> >         gcc_assert (VAR_P (decl));
> > -      return !DECL_EXTERNAL (decl);
> > +      return (!DECL_EXTERNAL (decl)
> > +         /* extern constexpr inline T foo{}; is a definition.  */
> > +         || (DECL_THIS_EXTERN (decl) && DECL_INITIAL (decl)));
> 
> I think we want something like
> 
> !DECL_EXTERNAL
> || DECL_INITIAL && !DECL_IN_AGGR_P
> 
> and yes, this should be a separate patch.

OK, I'll test this along with this v3.

> > -- >8 --
> > wrapup_namespace_globals gives errors for code like
> > 
> >    extern inline int i;
> >    int &r = i; // odr-used inline variable is not defined
> > 
> > but because we mark consteval-only vars DECL_EXTERNAL, we also wrongly
> > emit the error for:
> > 
> >    inline constexpr info value{};
> >    static_assert(value == info{});
> > 
> > where value clearly is defined.  This patch strenghtens the check to
> > also check DECL_THIS_EXTERN && !DECL_INITIAL.  We can't only check
> > the former because
> > 
> >    extern constexpr inline info v2{};
> > 
> > is OK.
> > 
> >     PR c++/124770
> > 
> > gcc/cp/ChangeLog:
> > 
> >     * decl.cc (wrapup_namespace_globals): Give the odr-used
> >     inline variable error for DECL_THIS_EXTERN variables only.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> >     * g++.dg/reflect/init18.C: New test.
> > ---
> >   gcc/cp/decl.cc                        |  7 +++++++
> >   gcc/testsuite/g++.dg/reflect/init18.C | 14 ++++++++++++++
> >   2 files changed, 21 insertions(+)
> >   create mode 100644 gcc/testsuite/g++.dg/reflect/init18.C
> > 
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index f8e9223e43e..4f59fab5e89 100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -1023,6 +1023,13 @@ wrapup_namespace_globals ()
> >       if (VAR_P (decl)
> >           && DECL_EXTERNAL (decl)
> > +         /* We mark consteval-only variables DECL_EXTERNAL, so check for
> > +            an explicit extern...  */
> > +         && DECL_THIS_EXTERN (decl)
> 
> I don't think we need to check both DECL_EXTERNAL and DECL_THIS_EXTERN,
> either one should work.  Maybe keep checking DECL_EXTERNAL for a smaller
> change and have just one comment.
> 
> > +         /* ...but
> > +             extern constexpr inline std::meta::info i{};
> > +            is a definition (the extern in redundant).  */
> 
> s/in/is/

So like this?  dg.exp passed, will do the full testing now.

-- >8 --
wrapup_namespace_globals gives errors for code like

  extern inline int i;
  int &r = i; // odr-used inline variable is not defined

but because we mark consteval-only vars DECL_EXTERNAL, we also wrongly
emit the error for:

  inline constexpr info value{};
  static_assert(value == info{});

where value clearly is defined.  This patch strenghtens the check to
also check !DECL_INITIAL.  We can't only check DECL_THIS_EXTERN because

  extern constexpr inline info v2{};

is OK.

        PR c++/124770

gcc/cp/ChangeLog:

        * decl.cc (wrapup_namespace_globals): Give the odr-used
        inline variable error only when !DECL_INITIAL.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/init18.C: New test.
---
 gcc/cp/decl.cc                        |  4 ++++
 gcc/testsuite/g++.dg/reflect/init18.C | 14 ++++++++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/reflect/init18.C

diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index f8e9223e43e..21a57d01dee 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1023,6 +1023,10 @@ wrapup_namespace_globals ()
 
          if (VAR_P (decl)
              && DECL_EXTERNAL (decl)
+             /* We mark consteval-only variables DECL_EXTERNAL, but
+                 extern constexpr inline std::meta::info i{};
+                is a definition (the extern is redundant).  */
+             && !DECL_INITIAL (decl)
              && DECL_INLINE_VAR_P (decl)
              && DECL_ODR_USED (decl))
            error_at (DECL_SOURCE_LOCATION (decl),
diff --git a/gcc/testsuite/g++.dg/reflect/init18.C 
b/gcc/testsuite/g++.dg/reflect/init18.C
new file mode 100644
index 00000000000..f13125be66e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/init18.C
@@ -0,0 +1,14 @@
+// PR c++/124770
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+using info = decltype(^^::);
+
+constexpr inline info v{};
+static_assert(v == info{});
+extern constexpr inline info v2{};
+static_assert(v2 == info{});
+constexpr inline info v3;
+static_assert(v3 == info{});
+
+extern constexpr inline info v4; // { dg-error "not a 
definition|consteval-only" }

base-commit: 6bae0c37c95565171657a15ab4dcfd13a6898769
-- 
2.54.0

Reply via email to