]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Remove gnu::gnu_inline attribute on inheriting ctors [PR123526]
authorJakub Jelinek <jakub@redhat.com>
Mon, 12 Jan 2026 09:05:50 +0000 (10:05 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 12 Jan 2026 09:05:50 +0000 (10:05 +0100)
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.

2026-01-12  Jakub Jelinek  <jakub@redhat.com>

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
gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor2.C [new file with mode: 0644]

index 9675f1ffcad3c82f9ec1a1e1e9acb9a6c76643da..e5ad3ac4494f7ddc9efc9a98cd4f15752653dac3 100644 (file)
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #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_kind kind, tree type,
       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);
     }
diff --git a/gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor1.C b/gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor1.C
new file mode 100644 (file)
index 0000000..11fcabb
--- /dev/null
@@ -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 ()
+{
+}
diff --git a/gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor2.C b/gcc/testsuite/g++.dg/ext/gnu-inline-inh-ctor2.C
new file mode 100644 (file)
index 0000000..4bc53bb
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/123526
+// { dg-do compile }
+
+struct A {
+  explicit A (int);
+  virtual ~A ();
+};
+
+A::A (int)
+{
+}
+
+A::~A ()
+{
+}