Bug 283917 - libc failes to include stdint.h with clang>16 and -ffreestanding
Summary: libc failes to include stdint.h with clang>16 and -ffreestanding
Status: Open
Alias: None
Product: Base System
Classification: Unclassified
Component: standards (show other bugs)
Version: 14.2-STABLE
Hardware: Any Any
: --- Affects Some People
Assignee: freebsd-standards (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2025-01-08 08:10 UTC by keve
Modified: 2025-01-17 17:11 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description keve 2025-01-08 08:10:41 UTC
The trivial code
```
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>

int
main(const int argc, const char *argv[])
{
	uint32_t answer = 42;
	printf("%" PRId32 "\n", answer);
	return 0;
}
```

fails to compile with clang17, clang18, clang19, when -ffreestanding is set


```
# env CC=clang19 CFLAGS=-ffreestanding make hello
clang19 -ffreestanding  hello.c  -o hello
In file included from hello.c:2:
/usr/local/llvm19/lib/clang/19/include/stdint.h:261:25: error: typedef redefinition with different types ('int16_t' (aka 'short') vs '__int_fast16_t' (aka 'int'))
  261 | typedef __int_least16_t int_fast16_t;
      |                         ^
/usr/include/sys/stdint.h:51:25: note: previous definition is here
   51 | typedef __int_fast16_t          int_fast16_t;
      |                                 ^
In file included from hello.c:2:
/usr/local/llvm19/lib/clang/19/include/stdint.h:262:26: error: typedef redefinition with different types ('uint16_t' (aka 'unsigned short') vs '__uint_fast16_t' (aka 'unsigned int'))
  262 | typedef __uint_least16_t uint_fast16_t;
      |                          ^
/usr/include/sys/stdint.h:56:26: note: previous definition is here
   56 | typedef __uint_fast16_t         uint_fast16_t;
      |                                 ^
In file included from hello.c:2:
/usr/local/llvm19/lib/clang/19/include/stdint.h:280:24: error: typedef redefinition with different types ('int8_t' (aka 'signed char') vs '__int_fast8_t' (aka 'int'))
  280 | typedef __int_least8_t int_fast8_t;
      |                        ^
/usr/include/sys/stdint.h:50:24: note: previous definition is here
   50 | typedef __int_fast8_t           int_fast8_t;
      |                                 ^
In file included from hello.c:2:
/usr/local/llvm19/lib/clang/19/include/stdint.h:281:25: error: typedef redefinition with different types ('uint8_t' (aka 'unsigned char') vs '__uint_fast8_t' (aka 'unsigned int'))
  281 | typedef __uint_least8_t uint_fast8_t;
      |                         ^
/usr/include/sys/stdint.h:55:25: note: previous definition is here
   55 | typedef __uint_fast8_t          uint_fast8_t;
      |                                 ^
4 errors generated.
*** Error code 1
```

Other environments (e.g. Linux, Darwin) compile this code just fine with -ffreestanding.


A real life project affected by this is e.g. libecc (https://github.com/libecc/libecc)
Comment 1 Konstantin Belousov freebsd_committer freebsd_triage 2025-01-08 13:01:09 UTC
FreeBSD libc is by definition a provider of ANSI C/POSIX library interfaces
for the hosted environment.  It cannot work this way.

If you want to use -ffreestanding, you at least must disallow use of the
standard system compilation environment (includes etc), perhaps by using
the -nostdinc option, at least.
Comment 2 keve 2025-01-08 13:40:26 UTC
Hi Konstantin, 
thank you for looking at this.
I tend to read it differently:


The ISO C standard defines (in clause 4) two classes of conforming implementation. A conforming hosted implementation supports the whole standard including all the library facilities; a conforming freestanding implementation is only required to provide certain library facilities: those in <float.h>, <limits.h>, <stdarg.h>, and <stddef.h>; since AMD1, also those in <iso646.h>; since C99, also those in <stdbool.h> and <stdint.h>; and since C11, also those in <stdalign.h> and <stdnoreturn.h>. In addition, complex types, added in C99, are not required for freestanding implementations.

So since C99 it is ok to assume presence of and include stdint.h even with -ffreestanding.
Clang starting with 17 implements C99.

Also the standard says that a freestanding implementation _may_ not implement these headers, it does not say anything about it _must_ not implement them.

Btw. just confirmed that  NetBSD 10.1 can compile this as well.

-nostdinc is unfortunately not a viable workaround.

Please reconsider your assessment whether this is an issue with FreeBSD libc, or not.

Thank you!
Comment 3 Konstantin Belousov freebsd_committer freebsd_triage 2025-01-09 00:52:06 UTC
What do you propose to reconsider?  The project goals?  The project aims to
provide the environment for executing unix programs, which are hosted by C std
definition.

That said, you do get the clang' project idea of freestanding environment when
you specify -ffreestanding.  But your 'trivial code' is not trivial, it uses
a lot of facilities from the FreeBSD hosted environment which surprisingly to
you do not mix with the clang' freestanding implementation.   Either use
only clang freestanding bits, or use only FreeBSD hosted env.
Comment 4 Mark Johnston freebsd_committer freebsd_triage 2025-01-17 17:11:23 UTC
Looking at LLVM's stdint.h, it does an #include_next <stdint.h>, which presumably pulls in the FreeBSD header, causing the failure.  Isn't that incorrect behaviour from LLVM when -ffreestanding is configured?  Which toolchain(s) are you using on other systems?