[LLVMbugs] [Bug 3989] C99 inline + extern decl merging problems

bugzilla-daemon at cs.uiuc.edu bugzilla-daemon at cs.uiuc.edu
Tue Jan 5 07:19:33 PST 2010


Douglas Gregor <dgregor at apple.com> changed:

           What    |Removed                     |Added
             Status|REOPENED                    |RESOLVED
         Resolution|                            |INVALID

--- Comment #11 from Douglas Gregor <dgregor at apple.com>  2010-01-05 09:19:32 ---
(In reply to comment #10)
> I'm not sure why this was marked as resolved/fixed ... perhaps it was fixed but
> has been broken again.
> I found this pre-existing report when thinking about reporting the same issue
> with r92723 from subversion.  The problem is that clang appears to be
> generating a reference to an external version of the function when no such
> external version can be assumed to exist, resulting in unresolved references at
> link time.

Clang is behaving correctly; see below.

> I wrote a test program containing a simple inline function x() called from
> main()
> Now this function is not declared extern or static, and is used in the file.
> As it's not declared 'extern' it can't depend on linking to an external
> version, yet the .o file produced by clang lists it as undefined so that the
> linker tries to resolve it.

That's not quite correct. Functions that do not have any storage specifier have
external linkage, so "x" can depend on linking to an external version.

> See http://www.greenend.org.uk/rjk/2003/03/inline.html for a nice summary of
> the rules about inline functions I found.

It's better to refer to the C99 spec, in which 6.7.4p6 says:

  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. An inline definition does not
provide an external definition for the function, and does not forbid an
external definition in another translation unit. An inline definition provides
an alternative to an external definition, which a translator may use to
implement any call to the function in the same translation unit. It is
unspecified whether a call to the function uses the inline definition or the
external definition.

Now, "x" is an "inline definition", since all of the file-scope declarations
have "inline" but not "extern". Then, the second sentence kicks in: an inline
definition does *not* provide an external definition in that translation unit,
meaning that we aren't allowed to emit a definition of "x" at all. Finally, the
last sentence says that C99 doesn't tell us which x() to call---the inline
definition defined here, or some other, external definition in another
translation unit. In practice, we end up calling the external definition when
optimization is turned off (default, -O0) and the inlined version when inlining
is turned on (-O2).

> Here's a log of the results of compiling this code unit with gcc (which seems
> to do the right thing) and with clang (followed by a listing of the test code):
> [richard at centos libobjc2]$ gcc a.c -std=c99 -c
> [richard at centos libobjc2]$ nm a.o | fgrep objc_read_int
> [richard at centos libobjc2]$ nm a.o | fgrep x
> 00000000 T x

This doesn't match what I'm seeing with gcc 4.2:

blackthorn:clang dgregor$ gcc a.c -std=c99 -c
blackthorn:clang dgregor$ nm a.o | fgrep objc_read_int
blackthorn:clang dgregor$ nm a.o | fgrep x
                 U _x

and it isn't correct, either: when compiling in C99 mode, GCC should not be
emitting an external definition for "x".

Note, however, that with the default language variant for GCC (gnu89), we will
get an external definition for "x", because GNU inline semantics are different
from C99 inline semantics. Clang defaults to C99, so this is a common source of

> [richard at centos libobjc2]$ clang a.c -std=c99 -c
> [richard at centos libobjc2]$ nm a.o | fgrep x
>          U x

This is correct behavior.

Configure bugmail: http://llvm.org/bugs/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
You are on the CC list for the bug.

More information about the llvm-bugs mailing list