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.
-- >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/
+ && !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: e8aa21caed8a3c8b4b27d224a04296f008bcf3da