On 5/7/26 3:38 PM, Marek Polacek wrote:
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.

OK.

-- >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

Reply via email to