There is a problem when the definition of an inline function is after the call. The following code shows the problem
inline void f(void);
void g1(void)
{
f();
}
inline void f(void)
{
}
void g2(void)
{
f();
}
The call to f() in g2() works as intended, but the one in g1() does not. This problem can be reproduced in sdcc revision #7126.
Philipp
Can you please be a bit more elaborate? What does "not work" mean? Do you get an error or is it just not inlined? I assume it perfectly executes "nothing".
The call is neither inlined, nor is a function body being generated, I thus get
?ASlink-Warning-Undefined Global '_f' referenced by module 'test'
Philipp
That seems correct to me.
The call does not need to be inlined. And the inline definition with external linkage should not generate an external definition (a function body implementation). You must provide one. The inline definition can only be used for inline replacement.
After re-reading the standard, it seems you are right: In my example the definition of f() is an inline definition which only providedes an alternative to a potentially existing external definition and the compiler is free to use the inline definition (as it does for g2()) or the external one (as it does for g1()).
The following is bases on my still shaky understanding of the standard, so I might be wrong again:
Making a small change to the testcase IMO makes it a bug: Add the following line at the end of the source file:
extern void f(void);
Now, according to the standard, we still have a definition of an inline function, but it no longer is an inline definition (verse 1540 (C99) "If all of the file scope declarations for a function in a translation unit include the inline function specifier without extern, then the definition in that translation unit is an inline definition." no longer applies. We even have an external definition now, which could be used from other translation units. Still, we might inline the calls to f() or not, but we no longer can produce a link error.
Another option would be to make f static and add a
static void f(void);
at the end of the file. Now we do not have an external definition, but it is not an inline definition either. WE have the option of inlining the calls or not, but we can't give a link error and we cannot create a definition visible by other translation units.
In all these cases, sdcc still gives the original error message "?ASlink-Warning-Undefined Global '_f' referenced by module 'test'".
Philipp
Sorry, the static case seems to work, but the cases of adding
extern inline void f(void);
or
extern void f(void);
or
void f(void);
do not.
Philipp
Both the inline definition case and static inline case are already tested by regression test inline.c. The external definition case apparently is not.
But I agree with you that the description in the spec is pretty difficult. That is probably also why many other compilers seem to get it wrong.
From the P99 test suite, I have created a test case for SDC inline issues. Two cases where SDCC should generate a function body, but doesn't.
Philipp
Diff:
Problem is reproduced in r11795
@spth's example still fails in SDCC 4.6.0: https://godbolt.org/z/v6WdG5aKP
I think the core of the ideal solution to this bug is the same as the core of the solution to [feature-requests:#414] : in both cases, SDDC needs to stop emitting code for function definitions as soon as it encounters them but instead retain a high-level representation of each function until the end of the translation unit, and only then emit code. This bug is about
inlinerather thanstaticbut at heart I think they are manifestations of the same issue.A vexing issue will be generation of diagnostics because unguarded uses of
_Optionalobjects are not diagnosed if the optimiser is not run. That implies that the optimiser should be run regardless of whether a function is known to comprise dead code.Related
Feature Requests: #414
Last edit: Christopher Bazley 7 days ago
Here's the fourth of a patch series created by Codex under my direction, of which the first three patches are attached to [feature-requests:#414]. It is far smaller than a stand-alone fix for this bug would have been. It decides whether an inline definition requires external emission after all declarations have been seen and preserves the parameter-allocation treatment of definitions originally parsed as inline-only. It also adds regression tests.
Related
Feature Requests: #414