[[always_inline]] attribute

3,375 views
Skip to first unread message

Flávio Lisbôa

unread,
Jan 17, 2018, 1:47:09 PM1/17/18
to ISO C++ Standard - Future Proposals
I searched in the forums but could not find a similar proposal. Instead, I found a discussion that may be related, but I'm not sure if my proposal completely fulfills the author's needs.

[[always_inline]] is a hint that would substitute __attribute__((always_inline)), __forceinline and similar compiler-specific hints. The intention is for it to be semantically different from C++'s inline (e.g. as a mechanism for ODR realization) and be more on par with the compiler-dependent attributes it substitutes and C99's inline (e.g. try to inline the function call to avoid stack growth).

Instead of using macros, like in:

#ifdef _MSC_VER
#   define always_inline __forceinline
#elif defined(__GNUC__)
#   define always_inline __attribute__((always_inline)) inline
#else
#   define always_inline inline
#endif

struct Test {
    always_inline void function() {}
}

One would use insead:

struct Test {
    [[always_inline]] void function() {}
}

It could be named [[try_inline]] or [[force_inline]], perhaps.

Was this discussed before? Could there be any unforeseen consequence if such an attribute was standardized? I don't believe it would change the semantic of the program (or perhaps it would, in the case of e.g. member function pointers? but then, again, it's just a hint).

Magnus Fromreide

unread,
Jan 17, 2018, 4:36:00 PM1/17/18
to std-pr...@isocpp.org
On Wed, Jan 17, 2018 at 10:47:09AM -0800, Flávio Lisbôa wrote:
> I searched in the forums but could not find a similar proposal. Instead, I found
> a discussion
> <https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/r1pWsCgV550>
> that may be related, but I'm not sure if my proposal completely fulfills
> the author's needs.
>
> [[always_inline]] is a hint that would substitute
> __attribute__((always_inline)), __forceinline and similar compiler-specific
> hints. The intention is for it to be semantically different from C++'s
> inline (e.g. as a mechanism for ODR realization) and be more on par with
> the compiler-dependent attributes it substitutes and C99's inline (e.g. try
> to inline the function call to avoid stack growth).

One of the points of always_inline is that the compiler ain't allowed to ignore
it. As such it can't be an attribute.

/MF

Tony V E

unread,
Jan 17, 2018, 5:03:20 PM1/17/18
to Standard Proposals
But it also can't be a keyword, as it is outside the language - the language doesn't define compiling to another representation (that may or may not mash functions together).
An implementation that interprets your code instead of compiling it could be a valid C++ implementation.

So an attribute is right, but the naming is tricky.

[[really_srsly_inline_please]
 
--
Be seeing you,
Tony

Nicol Bolas

unread,
Jan 17, 2018, 5:17:22 PM1/17/18
to ISO C++ Standard - Future Proposals
If the compiler doesn't implement the concept of `always_inline`, then I don't see the problem. That is, if the compiler has no compiler-specific inlining attribute, then it shouldn't be a surprise that [[always_inline]] won't inline it either.

What we want is a cross-platform way to say what we can already say. People who genuinely need forced inlining use compilers that support forced inlining. If some compiler can't do it, they simply won't use that compiler.

This is a QOI issue. Let compilers handle it as they see fit.

Erich Keane

unread,
Jan 17, 2018, 5:52:54 PM1/17/18
to ISO C++ Standard - Future Proposals
Thats not actually true.... always_inline means "do inlining on this function even in O0".  Some compilers will increase the required weight to cause the inlining, but they still make a decision based on whether to inline separately.

Andrey Semashev

unread,
Jan 17, 2018, 6:12:31 PM1/17/18
to std-pr...@isocpp.org
On 01/18/18 01:52, Erich Keane wrote:
> On Wednesday, January 17, 2018 at 1:36:00 PM UTC-8, Magnus Fromreide wrote:
> On Wed, Jan 17, 2018 at 10:47:09AM -0800, Flávio Lisbôa wrote:
> > I searched in the forums but could not find a similar proposal.
> Instead, I found
> > a discussion
> >
> <https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/r1pWsCgV550
> <https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/r1pWsCgV550>>
>
> > that may be related, but I'm not sure if my proposal completely
> fulfills
> > the author's needs.
> >
> > [[always_inline]] is a hint that would substitute
> > __attribute__((always_inline)), __forceinline and similar
> compiler-specific
> > hints. The intention is for it to be semantically different from
> C++'s
> > inline (e.g. as a mechanism for ODR realization) and be more on
> par with
> > the compiler-dependent attributes it substitutes and C99's inline
> (e.g. try
> > to inline the function call to avoid stack growth).
>
> One of the points of always_inline is that the compiler ain't
> allowed to ignore
> it. As such it can't be an attribute.
>
> Thats not actually true.... always_inline means "do inlining on this
> function even in O0".

It's not even that strong, not in case of gcc, at least. Basically,
__attribute__((always_inline)) makes the function always inlined _when
it is considered for inlining by the optimizer_. -O0 disables the
optimizer entirely, making the attribute have no effect.

Arthur O'Dwyer

unread,
Jan 17, 2018, 6:28:10 PM1/17/18
to ISO C++ Standard - Future Proposals
On Wednesday, January 17, 2018 at 10:47:09 AM UTC-8, Flávio Lisbôa wrote:

[[always_inline]] is a hint that would substitute __attribute__((always_inline)), __forceinline and similar compiler-specific hints. The intention is for it to be semantically different from C++'s inline (e.g. as a mechanism for ODR realization) and be more on par with the compiler-dependent attributes it substitutes and C99's inline (e.g. try to inline the function call to avoid stack growth).
[...snip highly motivating example code...]
Was this discussed before? Could there be any unforeseen consequence if such an attribute was standardized? I don't believe it would change the semantic of the program (or perhaps it would, in the case of e.g. member function pointers? but then, again, it's just a hint).

Yep, seems like a slam-dunk to me. (And [[always_inline]] is the correct name, for historical reasons. Let's not inflict another NIHism like [[maybe_unused]] on the world. Although I'll admit, even though I resented [[nodiscard]] at the time, it's probably a good thing that we no longer have to teach the historically-correct but impossible-to-remember [[warn_unused_result]].)

Kind of a thread-hijack, but I have thought for a long time that what would be really nice in a C-style language is a reification of something kind of like Lisa Lippincott's "basic interface" ideas. In the following metaphor, the function call-site is like a Javascript client, and the out-of-line function body is like a remote server. Quite often we have a function with a bunch of (metaphorical) "client-side checks" stuffed in front of the "server-side code":

    extern int some_function_unchecked(int *x, int n, int i);
    inline int some_function(int *x, int n, int i) {
        if (x == nullptr) throw "oops";
        if (n < 0) throw "oops";
        if (!(0 <= i && i < n)) return 0;
        return some_function_unchecked(x, n, i);
    }

and it would be nice to indicate directly to the compiler, without having to play tricks with helper functions, that those "client-side checks" should be inlined, and then the (metaphorical) "server-side logic" should not be inlined. Because if you can inline the "client-side checks," you'll usually find that they are optimized out entirely; whereas the benefit of inlining the "server-side logic" might actually be negative.

So this is what I think of whenever anyone suggests modifying the core language around inlining.
But really, just getting a standard/portable C++11-style synonym for [[always_inline]] would be an improvement on the status quo.

FYI, for at least GCC and Clang, you can use [[gnu::always_inline]].  (I *think* Clang is respecting it, not just ignoring it.)

–Arthur

Tony V E

unread,
Jan 17, 2018, 7:20:50 PM1/17/18
to Standard Proposals
On Wed, Jan 17, 2018 at 6:28 PM, Arthur O'Dwyer <arthur....@gmail.com> wrote:
On Wednesday, January 17, 2018 at 10:47:09 AM UTC-8, Flávio Lisbôa wrote:

[[always_inline]] is a hint that would substitute __attribute__((always_inline)), __forceinline and similar compiler-specific hints. The intention is for it to be semantically different from C++'s inline (e.g. as a mechanism for ODR realization) and be more on par with the compiler-dependent attributes it substitutes and C99's inline (e.g. try to inline the function call to avoid stack growth).
[...snip highly motivating example code...]
Was this discussed before? Could there be any unforeseen consequence if such an attribute was standardized? I don't believe it would change the semantic of the program (or perhaps it would, in the case of e.g. member function pointers? but then, again, it's just a hint).

Yep, seems like a slam-dunk to me. (And [[always_inline]] is the correct name, for historical reasons. Let's not inflict another NIHism like [[maybe_unused]] on the world. Although I'll admit, even though I resented [[nodiscard]] at the time, it's probably a good thing that we no longer have to teach the historically-correct but impossible-to-remember [[warn_unused_result]].)

Kind of a thread-hijack, but I have thought for a long time that what would be really nice in a C-style language is a reification of something kind of like Lisa Lippincott's "basic interface" ideas. In the following metaphor, the function call-site is like a Javascript client, and the out-of-line function body is like a remote server. Quite often we have a function with a bunch of (metaphorical) "client-side checks" stuffed in front of the "server-side code":

    extern int some_function_unchecked(int *x, int n, int i);
    inline int some_function(int *x, int n, int i) {
        if (x == nullptr) throw "oops";
        if (n < 0) throw "oops";
        if (!(0 <= i && i < n)) return 0;
        return some_function_unchecked(x, n, i);
    }

and it would be nice to indicate directly to the compiler, without having to play tricks with helper functions, that those "client-side checks" should be inlined, and then the (metaphorical) "server-side logic" should not be inlined. Because if you can inline the "client-side checks," you'll usually find that they are optimized out entirely; whereas the benefit of inlining the "server-side logic" might actually be negative.

I really like that idea (and all of the bigger stuff from Lisa's work).
No idea what the syntax would be, other than { } with an annotation, like [[no_inline]] for that block.

Richard Smith

unread,
Jan 17, 2018, 7:23:32 PM1/17/18
to std-pr...@isocpp.org
Your claim is trivially falsified: https://godbolt.org/g/bahckm

And the GCC documentation explicitly covers this, saying "GCC does not inline any functions when not optimizing unless you specify the ‘always_inline’ attribute for the function".

The actual rules for the attribute are (per the GCC documentation):

"""
always_inline

Generally, functions are not inlined unless optimization is specified. For functions declared inline, this attribute inlines the function independent of any restrictions that otherwise apply to inlining. Failure to inline such a function is diagnosed as an error. Note that if such a function is called indirectly the compiler may or may not inline it depending on optimization level and a failure to inline an indirect call may or may not be diagnosed.
"""

gmis...@gmail.com

unread,
Jan 17, 2018, 8:35:13 PM1/17/18
to ISO C++ Standard - Future Proposals
Richard
I think the OP's idea to standardize always inline is a good one
I generally find the rules on when functions are inlined or not a bit confusing.
It seems it would be good to standardize this area if possible?
In that aim, if we are going to address always inline which I'd like, it seems it would make sense for the Standard to address no inline. i.e.:
msvc and gcc and clang all seem to have noinline so it would be good if that could be standardized.

Thiago Macieira

unread,
Jan 17, 2018, 9:45:19 PM1/17/18
to std-pr...@isocpp.org
On Wednesday, 17 January 2018 13:35:53 PST Magnus Fromreide wrote:
> One of the points of always_inline is that the compiler ain't allowed to
> ignore it. As such it can't be an attribute.

Actually, it is, because inlining has no visible behaviour. A function that is
inlined behaves exactly the same way as its not-inlined copy. ODR still
applies.

The difference is whether it can be used without the inline keyword. The MSVC
__forceinline keyword replaces inline and forces the inlining, whereas the GCC
& family __attribute__((inline)) attribute is just a very strong hint, but
does not actually replace the inline keyword.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center



Bo Persson

unread,
Jan 18, 2018, 8:03:53 AM1/18/18
to std-pr...@isocpp.org
On 2018-01-18 03:45, Thiago Macieira wrote:
> On Wednesday, 17 January 2018 13:35:53 PST Magnus Fromreide wrote:
>> One of the points of always_inline is that the compiler ain't allowed to
>> ignore it. As such it can't be an attribute.
>
> Actually, it is, because inlining has no visible behaviour. A function that is
> inlined behaves exactly the same way as its not-inlined copy. ODR still
> applies.
>
> The difference is whether it can be used without the inline keyword. The MSVC
> __forceinline keyword replaces inline and forces the inlining, whereas the GCC
> & family __attribute__((inline)) attribute is just a very strong hint, but
> does not actually replace the inline keyword.
>

The __forceinline doesn't actually force inlining either, it is just a
strong hint as well. In some cases the compiler is not ABLE to inline
some function, period.

Historically this has been everything from functions with a local array,
functions returning a large, complex object or an object with a throwing
copy constructor, to having local objects with a throwing destructor.

Where are we going to set the bar?


Bo Persson

Andrey Semashev

unread,
Jan 18, 2018, 12:49:13 PM1/18/18
to std-pr...@isocpp.org
On 01/18/18 03:23, Richard Smith wrote:
> On 17 January 2018 at 15:12, Andrey Semashev <andrey....@gmail.com
Hmm, I was sure I've seen cases when gcc would not inline functions with
-O0 and would inline on higher optimization levels. I think, it happened
in the context of Boost.Atomic and ultimately caused atomic operations
to always have seq_cst semantics regardless of what the user specified.
Maybe I'm misremembering the cause of the problem...

Flávio Lisbôa

unread,
Jan 18, 2018, 3:56:54 PM1/18/18
to ISO C++ Standard - Future Proposals
I agree with you. The language doesn't make it clear when inlining occurs, and in fact I believe it does not even talk about such an optimization, so a programmer must know some implementation detail to optimize in this case.

Still, inlining is something that all common compilers can do in one way or another for a long time. If we have have [[deprecated]], [[noreturn]] and others, as a way to standardize common compiler attributes, I don't see why an [[always_inline]] (or whatever it's named) could be done as well. If the compiler doesn't implement (or disables) inlining, I believe the attribute can be safely ignored, and the function can be compiled as part of a translation unit, respecting ODR as usual.

In the specific case of GCC's always_inline, I think [[always_inline]] would be a misnomer, or some other attribute should be used, because GCC diagnoses the program with an error in case inlining is not possible. I believe this would change program semantics, wouldn't it? An example: https://godbolt.org/g/eBqrBM (I understand this example is a bit far-fetched, but still...)

If not an attribute, should the language introduce inlining at the language level instead (I mean, as in C99)?

Flávio Lisbôa

unread,
Jan 18, 2018, 3:57:46 PM1/18/18
to ISO C++ Standard - Future Proposals
I fully agree with that. In fact, I was thinking about adding this suggestion to the discussion. :)

Tony V E

unread,
Jan 18, 2018, 4:46:54 PM1/18/18
to Standard Proposals
On Thu, Jan 18, 2018 at 3:56 PM, Flávio Lisbôa <flisbo...@gmail.com> wrote:
I agree with you. The language doesn't make it clear when inlining occurs, and in fact I believe it does not even talk about such an optimization, so a programmer must know some implementation detail to optimize in this case.

Still, inlining is something that all common compilers can do in one way or another for a long time. If we have have [[deprecated]], [[noreturn]] and others, as a way to standardize common compiler attributes, I don't see why an [[always_inline]] (or whatever it's named) could be done as well. If the compiler doesn't implement (or disables) inlining, I believe the attribute can be safely ignored, and the function can be compiled as part of a translation unit, respecting ODR as usual.

In the specific case of GCC's always_inline, I think [[always_inline]] would be a misnomer, or some other attribute should be used, because GCC diagnoses the program with an error in case inlining is not possible. I believe this would change program semantics, wouldn't it? An example: https://godbolt.org/g/eBqrBM (I understand this example is a bit far-fetched, but still...)

If not an attribute, should the language introduce inlining at the language level instead (I mean, as in C99)?


It CANNOT be done at the language level.  It has no meaning at the language level.


Magnus Fromreide

unread,
Jan 19, 2018, 2:17:53 AM1/19/18
to std-pr...@isocpp.org
On Wed, Jan 17, 2018 at 02:17:22PM -0800, Nicol Bolas wrote:
> On Wednesday, January 17, 2018 at 4:36:00 PM UTC-5, Magnus Fromreide wrote:
> >
> > On Wed, Jan 17, 2018 at 10:47:09AM -0800, Flávio Lisbôa wrote:
> > > I searched in the forums but could not find a similar proposal. Instead,
> > I found
> > > a discussion
> > > <
> > https://groups.google.com/a/isocpp.org/forum/#!topic/std-proposals/r1pWsCgV550>
> >
> > > that may be related, but I'm not sure if my proposal completely fulfills
> > > the author's needs.
> > >
> > > [[always_inline]] is a hint that would substitute
> > > __attribute__((always_inline)), __forceinline and similar
> > compiler-specific
> > > hints. The intention is for it to be semantically different from C++'s
> > > inline (e.g. as a mechanism for ODR realization) and be more on par with
> > > the compiler-dependent attributes it substitutes and C99's inline (e.g.
> > try
> > > to inline the function call to avoid stack growth).
> >
> > One of the points of always_inline is that the compiler ain't allowed to
> > ignore
> > it. As such it can't be an attribute.
> >
>
> If the compiler doesn't implement the concept of `always_inline`, then I
> don't see the problem. That is, if the compiler has no compiler-specific
> inlining attribute, then it shouldn't be a surprise that [[always_inline]]
> won't inline it either.

But an always_inline attribute that fails to always inline is obviously
misnamed.

> What we want is a cross-platform way to say what we can already say.

I agree that this would be a good thing, but there seem to be some disagreement
regarding what it is we want to say here.

> People
> who genuinely need forced inlining use compilers that support forced
> inlining. If some compiler can't do it, they simply won't use that compiler.

So, you are telling me that I should use some magic at other places to detect
if [[always_inline]] actually do inline at all times as opposed to the
current state where I have to do some compiler-specific trickery.

I would then claim that

#ifdef __GNUC__
#define ALWAYS_INLINE __attribute__((always_inline))
#else
#error "No ALWAYS_INLINE on this compiler"
#endif

is better than the proposed

[[always_inline]]

since the former gives a hard error when the compiler ain't supporting it
while the latter is mandated to be silently ignored.

If I want to send the compiler a hint that some function should be inlined then
the language already provides that via the "inline" keyword so this proposed
[[always_inline]] will just provide a strength of the inlining hint,

Now, that is also a resonable idea but then it should be an attribute on the
inline keyword since that is what it affects:

inline [[inline_harder]] void fun() { /* */ }

but the name "always_inline" should not be used unlees you have the GCC
semantics of it beeing an error to fail to inline the function and in that
case it can't be an attribute.

I think one could express this in standardeese like this:

* The "always_inline" keyword ensures that the function declared so have no
linkage.

This is similar to how "static" ensures no external linkage or how "inline"
allows vague linkage.

> This is a QOI issue. Let compilers handle it as they see fit.

I'd rather se no standardization here than a standardization of a broken
concept.

/MF

Andrey Semashev

unread,
Jan 19, 2018, 5:16:06 AM1/19/18
to std-pr...@isocpp.org
That's not necessarily the case. The program can be written to be
portable across compilers and use [[always_inline]] or whatever the
attribute name is. Users can test their compiler and see that it doesn't
actually inline the functions. Arguably, this results in bad
performance, so the users probably pick another compiler.

The point here is that there is benefit for the program developers
because they can just use [[always_inline]] portably, without having to
check for the particular compilers, possibly missing out some of them.
There may be benefit for users of the program, if their compiler was not
previously supported by it, when it did compiler-specific tricks like
__forceinline. For those unlucky few whose compiler genuinely does not
support forced inlining nothing changes - they had poor performance
before and they still have it now.

Forced inlining is not something unique. All major compilers have
support for it, so having it available under the same name would be useful.

Nicol Bolas

unread,
Jan 19, 2018, 4:39:31 PM1/19/18
to ISO C++ Standard - Future Proposals
But since you cannot tell whether a function is inlined or not, what does it matter to the standard?

> What we want is a cross-platform way to say what we can already say.

I agree that this would be a good thing, but there seem to be some disagreement
regarding what it is we want to say here.

> People
> who genuinely need forced inlining use compilers that support forced
> inlining. If some compiler can't do it, they simply won't use that compiler.

So, you are telling me that I should use some magic at other places to detect
if [[always_inline]] actually do inline at all times as opposed to the
current state where I have to do some compiler-specific trickery.

But here's the thing: the cases you're talking about would provoke a compile error if it wasn't inlined. Since the standard cannot define the circumstances where this could happen, there is no portable way for you to enforce inlining to such a degree.

That is, consider this function:

[[always_inline]] void foo()
{
 
...
}

What is the `...` here that could cause use of this function to fail to compile? If you can't spell that out, then any code you write there is non-portable.

I would then claim that

#ifdef __GNUC__
#define ALWAYS_INLINE __attribute__((always_inline))
#else
#error "No ALWAYS_INLINE on this compiler"
#endif

is better than the proposed

[[always_inline]]

since the former gives a hard error when the compiler ain't supporting it
while the latter is mandated to be silently ignored.
 
If I want to send the compiler a hint that some function should be inlined then
the language already provides that via the "inline" keyword so this proposed
[[always_inline]] will just provide a strength of the inlining hint,

 
Now, that is also a resonable idea but then it should be an attribute on the
inline keyword since that is what it affects:

inline [[inline_harder]] void fun() { /* */ }

but the name "always_inline" should not be used unlees you have the GCC
semantics of it beeing an error to fail to inline the function and in that
case it can't be an attribute.

I think one could express this in standardeese like this:

* The "always_inline" keyword ensures that the function declared so have no
  linkage.

This is similar to how "static" ensures no external linkage or how "inline"
allows vague linkage.

`inline` does not cause "vague linkage". It cause internal linkage. That's a very specific kind of linkage.

Also, I fail to see how "no linkage" is equivalent to enforced inlining. In order to enforce inlining, you have to say something about whether inlining is possible in specific circumstances. And what inlining is, for that matter.

Linkage is ultimately about the accessibility of the name of an entity. Forced inlining is about more than that; here, you're saying that the entity flat-out doesn't exist.

> This is a QOI issue. Let compilers handle it as they see fit.

I'd rather se no standardization here than a standardization of a broken
concept.

And yet you're fine with GCC's "always_inline" which, as previously shown, isn't always inline so much as "almost always inline".
Reply all
Reply to author
Forward
0 new messages