On 1/12/26 8:17 AM, Jakub Jelinek wrote:
Hi!
The recent addition of gnu::gnu_inline attributes to some C++26 constexpr
methods broke classes which inherit e.g. from std::logic_error or other
C++26 classes with gnu::gnu_inline constructors and use inheriting
constructors. On std::logic_error etc. it has the desired effect that
the ctor itself can be constexpr evaluated and even inlined, but is not
emitted in each TU that needs it and didn't inline it, but is still
contained in libstdc++.{a,so.6}.
Unfortunately inheriting ctors inherit also attributes of the corresponding
ctors except those that clone_attrs filter out and that includes the
gnu_inline attribute if explicitly specified on the base class ctor.
That has the undesirable effect that the implementation detail of e.g.
the std::logic_error class leaks into the behavior of a class that inherits
from it if it is using inheriting constructors, those will result in
undefined symbols for the inheriting constructors if they aren't inlined,
unless one also inherits from it in some TU without gnu_inline there (e.g.
one compiled with -std=c++23 or earlier).
So, the following patch fixes it by removing the gnu::gnu_inline attribute
from the inheriting constructor. Not done in clone_attrs because that
function is also used for the normal constructor cloning and in that case
we do want to clone those attributes.
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK.
2026-01-12 Jakub Jelinek <[email protected]>
PR c++/123526
* method.cc: Include attribs.h.
(implicitly_declare_fn): Remove gnu::gnu_inline attribute.
* g++.dg/ext/gnu-inline-inh-ctor1.C: New test.
* g++.dg/ext/gnu-inline-inh-ctor2.C: New test.
--- gcc/cp/method.cc.jj 2026-01-02 09:56:10.106337546 +0100
+++ gcc/cp/method.cc 2026-01-12 00:01:56.298976985 +0100
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.
#include "toplev.h"
#include "intl.h"
#include "common/common-target.h"
+#include "attribs.h"
static void do_build_copy_assign (tree);
static void do_build_copy_constructor (tree);
@@ -3595,6 +3596,9 @@ implicitly_declare_fn (special_function_
tree inherited_ctor_fn = STRIP_TEMPLATE (inherited_ctor);
/* Also copy any attributes. */
DECL_ATTRIBUTES (fn) = clone_attrs (DECL_ATTRIBUTES
(inherited_ctor_fn));
+ /* But remove gnu::gnu_inline attribute. See PR123526. */
+ DECL_ATTRIBUTES (fn)
+ = remove_attribute ("gnu", "gnu_inline", DECL_ATTRIBUTES (fn));
DECL_DISREGARD_INLINE_LIMITS (fn)
= DECL_DISREGARD_INLINE_LIMITS (inherited_ctor_fn);
}
--- gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor1.C.jj 2026-01-12
00:02:22.694445009 +0100
+++ gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor1.C 2026-01-12
00:32:15.569956098 +0100
@@ -0,0 +1,22 @@
+// PR c++/123526
+// { dg-do link { target c++26 } }
+// { dg-options "-O0" }
+// { dg-additional-sources "gnu-inline-inh-ctor2.C" }
+
+struct A {
+ [[__gnu__::__gnu_inline__]]
+ constexpr explicit A (int) {}
+ [[__gnu__::__gnu_inline__]]
+ constexpr virtual ~A () {}
+};
+struct B : A {
+ using A::A;
+};
+constexpr B b (42);
+int c = 42;
+B d (c);
+
+int
+main ()
+{
+}
--- gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor2.C.jj 2026-01-12
00:02:25.619395258 +0100
+++ gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor2.C 2026-01-12
00:02:46.879033644 +0100
@@ -0,0 +1,15 @@
+// PR c++/123526
+// { dg-do compile }
+
+struct A {
+ explicit A (int);
+ virtual ~A ();
+};
+
+A::A (int)
+{
+}
+
+A::~A ()
+{
+}
Jakub