On Fri, Jan 02, 2026 at 10:56:45AM +0700, Jason Merrill wrote:
> Hmm, I would think we want something closer to gnu_inline that specifically
> affects linkage, without the other effects; it seems desirable to be able to
> inline these functions outside of constant evaluation as well.

Seems we already do support the gnu_inline extern inline behavior for
namespace scope functions as well as member functions if just
declared constexpr and gnu_inline inside of the class and defined
extern constexpr right after the class (but the dtor if any needs to be
defined first), e.g. -O2

[[gnu::gnu_inline]] extern constexpr int foo (int x) { return x + 42; }
static_assert (foo (0) == 42);
int bar (int x) { return foo (x); }
auto p = &foo;
struct S {
  [[gnu::gnu_inline]] constexpr int qux (int);
  [[gnu::gnu_inline]] constexpr virtual int garply (int);
  [[gnu::gnu_inline]] constexpr virtual ~S ();
};
[[gnu::gnu_inline]] extern constexpr S::~S () {}
[[gnu::gnu_inline]] extern constexpr int S::qux (int x) { return x + 42; }
[[gnu::gnu_inline]] extern constexpr int S::garply (int x) { return x + 43; }
static_assert (S {}.qux (0) == 42);
static_assert (S {}.garply (0) == 43);
int freddy (S s, int x) { return s.qux (x); }
int corge (S s, int x) { return s.garply (x); }
auto q = &S::qux;
int plugh (S &s, int x) { return s.garply (x); }
S s;

and in all cases we get the extern inline gnu_inline behavior, i.e.
what can be inlined is, what is not results in an external reference.

With the S s; line we get the vtable & rtti stuff in the TU though, which
would be nice to get rid of.

Plus clang++ handles it differently, with just constexpr it complains
warning: 'gnu_inline' attribute requires function to be marked 'inline', 
attribute ignored [-Wignored-attributes]
many times and with s/constexpr/constexpr inline/
warning: 'gnu_inline' attribute without 'extern' in C++ treated as externally 
available, this changed in Clang 10 [-Wgnu-inline-cpp-without-extern]
Sure, we could use gnu_inline attributes only for non-clang.

And, there is no clean way to actually define the out of line definition.
The normal way of
[[gnu::gnu_inline]] extern inline int foo (int x) { return x + 42; }
int foo (int x) { return x + 42; }
doesn't work when foo is constexpr on the first declaration.
Sure, for libstdc++ we actually define at least the currently needed ones
with different -std=c++NN and the header doesn't provide constexpr in that
version, so it works.

Thus, either we need just some new attribute that will say the gnu_inline
constexpr method can be a key method (at least when just declared and not
defined in the class), or perhaps a pair of attributes, one will on a
constexpr member function definition inside of class pretend it is extern
and can be a key method (so one could just write
struct S {
  [[gnu::whatever1]] constexpr int qux (int x) { return x + 42; }
  [[gnu::whatever1]] constexpr virtual int garply (int x) { return x + 43; }
  [[gnu::whatever1]] constexpr virtual ~S () {}
};
and get the above behavior anyway (i.e. extern inline gnu_inline) and
perhaps key method, and another attribute that one could use in the TU with
out of line definition and just force the inline definition to be out of
line that way, so one would do just
[[gnu::whatever2]] int S::qux (int);
[[gnu::whatever2]] int S::garply (int);
[[gnu::whatever2]] S::~S ();
and get the out of line definitions from the inline bodies that way.

        Jakub

Reply via email to