C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Drop same sequence of tokens for inline

From: David Brown <david_at_[hidden]>
Date: Fri, 5 May 2023 09:03:45 +0200
On 05/05/2023 03:22, Thiago Macieira via Std-Proposals wrote:
> On Thursday, 4 May 2023 17:54:12 PDT Alejandro Colomar wrote:
>> I still don't understand how use of static within an inline function
>> is not UB. Maybe in C++ it's useful. In C, I never found a need for
>> 'static' within an inline function.
>
> Indeed, but I'd say that it's a consequence of how statics inside inline were
> defined in C. That removed their usefulness, therefore they don't get used. The
> warning also probably exists because people tried to use it and have run into
> issues.
>

Modifiable statics inside non-static inline functions are not allowed in
C - it's a constraint error.

 From the standard, 6.7.4 ("Function specifiers") :

p3:
"""
An inline definition of a function with external linkage shall not
contain a definition of a modifiable object with static or thread
storage duration, and shall not contain a reference to an identifier
with internal linkage.
"""


If the inline function is "static inline", then it is just like any
other static function.

You can have "static const" variables inside a non-static inline
function - in C, these are initialised with constant values before
main() starts up.

> Static variables inside inline functions aren't that common in C++, except for
> a few very common patterns, such as that of singletons:
>
> class MySingleton
> {
> MySingleton();
> ~MySingleton();
> public:
> static MySingleton *instance()
> {
> static MySingleton self;
> return &self;
> }
> };
>
> Replacing this with a namespace- or class-scope static is not the same thing
> because it changes the lifetime of the object and it may be important that
> this constructor not be run at load time. At a minimum, this is lazy
> initialisation and conforms to "Don't Pay for What You Don't Need" ethos. It
> is possible to write code that keep the ethos and uses a non-vague variable,
> but it requires writing more code; a great deal more if you want to also have
> the thread- and exception-safety guarantee the code above gives you
> implicitly.
>
>> Is there any way to get UB without 'static' in compatible definitions such
>> as these?
>
> Yes, it's possible. The compiler is allowed to break your function into blocks
> and inline a portion of it and not another. GCC does this quite a lot when it
> decides some expensive code is unlikely. Take this example:
>
> void other();
> inline void f1(int i)
> {
> if (i)
> other();
> else
> throw i;
> }
>
> Modern GCC considers that throwing code is unlikely, just as if you had a
> [[likely]] attribute on that first if or __builtin_expected, so it moves the
> else branch to a separate block. You can see it in action in
> <https://gcc.godbolt.org/z/ns6Ph51Go>; note how there's a symbol with "[clone
> .cold]" suffix (if you turn on directives, you'll see that it's even in an
> entirely different section of the executable).

This is a completely different concept from the "inline" keyword.

Historically, the "inline" keyword was added to C and C++ as a compiler
hint, in the days of weaker compilers. These days, compilers make their
own decisions (influenced by compiler flags, pragmas, compiler-specific
attributes, etc.) about code generation. The compiler will inline some
or all of a function with a total disregard for the "inline" keyword.
It will also happily outline code that happens to be within a function
declared "inline".

It is important to concentrate on the semantics of "inline" - what it
actually means in the code. (It is also important to consider what it
means to people reading the code.) Leave the code generation details to
the compiler.


>
> Note also how this is not a new function obeying the regular calling
> convention, but really just a portion of the original and it expects the value
> to be thrown to be in the %eax register. So two different TUs did something
> different and innocent before that if, the register allocation might be
> different and result in garbage. UB.
>
> However, I do note in this case that the [clone .cold] applies to f(int),
> which is not the inline function but the non-inline one into which got f()
> inlined. So this particular version of the compiler wouldn't suffer from that
> problem.
>

Received on 2023-05-05 07:03:54