Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -101,6 +101,13 @@ which introduces the ``bool``, ``static_assert``, ``alignas``, ``alignof``, and ``thread_local`` keywords in C2x. +- Added ```` to the list of headers supported by freestanding + compilations. This partially implements + `WG14 N2524 `_, + but does not yet support ``memccpy``, ``memset_explicit``, or ``strtok`` yet. + NB, Clang does not yet support WG14 N3020 yet either, which impacts the + signatures of the functions in ````. + Non-comprehensive list of changes in this release ------------------------------------------------- - Clang now saves the address of ABI-indirect function parameters on the stack, Index: clang/lib/Headers/CMakeLists.txt =================================================================== --- clang/lib/Headers/CMakeLists.txt +++ clang/lib/Headers/CMakeLists.txt @@ -16,6 +16,7 @@ __stddef_max_align_t.h stdint.h stdnoreturn.h + string.h tgmath.h unwind.h varargs.h Index: clang/lib/Headers/string.h =================================================================== --- /dev/null +++ clang/lib/Headers/string.h @@ -0,0 +1,94 @@ +/*===---- string.h - Standard header for freestanding string facilities----===*\ + * + * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. + * See https://llvm.org/LICENSE.txt for license information. + * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + * +\*===----------------------------------------------------------------------===*/ + +#ifndef __CLANG_STRING_H +/* If we're hosted or in C17 or earlier, use the system string.h if it's + * available. + * FIXME: This is using the placeholder dates Clang produces for these macros + * in C2x mode; switch to the correct values once they've been published. + */ +#if (__STDC_HOSTED__ || \ + (defined(__STDC_VERSION__) && __STDC_VERSION__ < 202000L)) && \ + __has_include_next() +#include_next +#else + +/* C2x 7.26.1p2 */ +/* FIXME: Once we support memccpy, strtok, and memset_explicit, set this value + * to 202311L as required by the standard. For now, we use an older value. + */ +#define __STDC_VERSION_STRING_H__ 202300L + +/* C2x Clause 4p6: ... the features specified in the header are + * used, except the following functions: + * strdup, strndup, strcoll, strxfrm, strerror; and/or, ... + */ + +/* Copying Functions + * + * void *memcpy(void * restrict s1, const void * restrict s2, size_t n); + * FIXME: void *memccpy(void * restrict s1, const void * restrict s2, int c, + size_t n); + * void *memmove(void *s1, const void *s2, size_t n); + * char *strcpy(char * restrict s1, const char * restrict s2); + * char *strncpy(const * restrict s1, const char * restruct s2, size_t n); + */ +#define memcpy(__s1, __s2, __n) __builtin_memcpy(__s1, __s2, __n) +#define memmove(__s1, __s2, __n) __builtin_memmove(__s1, __s2, __n) +#define strcpy(__s1, __s2) __builtin_strcpy(__s1, __s2) +#define strncpy(__s1, __s2, __n) __builtin_strncpy(__s1, __s2, __n) + +/* Concatenation Functions + * + * char *strcat(char * restrict s1, const char * restrict s2); + * char *strncat(char * restrict s1, const char * restrict s2, size_t n); + */ +#define strcat(__s1, __s2) __builtin_strcat(__s1, __s2) +#define strncat(__s1, __s2, __n) __builtin_strncat(__s1, __s2, __n) + +/* Comparison Functions + * + * int memcmp(const void *s1, const void *s2, size_t n); + * int strcmp(const char *s1, const char *s2); + * int strncmp(const char *s1, const char *s2, size_t n); + */ +#define memcmp(__s1, __s2, __n) __builtin_memcmp(__s1, __s2, __n) +#define strcmp(__s1, __s2) __builtin_strcmp(__s1, __s2) +#define strncmp(__s1, __s2, __n) __builtin_strncmp(__s1, __s2, __n) + +/* Search Functions + * + * QVoid *memchr(QVoid *s, int c, size_t n); + * QChar *strchr(QChar *s, int c); + * size_t strcspn(const char *s1, const char *s2); + * QChar *strpbrk(QChar *s1, const char *s2); + * QChar *strrchr(QChar *s1, int c); + * size_t strspn(const char *s1, const char *s2); + * QChar *strstr(QChar *s1, const char *s2); + * FIXME: char *strtok(char * restrict s1, const char * restrict s2); + */ +#define memchr(__s, __c, __n) __builtin_memchr(__s, __c, __n) +#define strchr(__s, __c) __builtin_strchr(__s, __c) +#define strcspn(__s1, __s2) __builtin_strcspn(__s1, __s2) +#define strpbrk(__s1, __s2) __builtin_strpbrk(__s1, __s2) +#define strrchr(__s1, __c) __builtin_strrchr(__s1, __c) +#define strspn(__s1, __s2) __builtin_strspn(__s1, __s2) +#define strstr(__s1, __s2) __builtin_strstr(__s1, __s2) + +/* Miscellaneous Functions + * + * void *memset(void *s, int c, size_t n); + * FIXME: void *memset_explicit(void *s, int c, size_t n); + * size_t strlen(const char *s); + */ +#define memset(__s, __c, __n) __builtin_memset(__s, __c, __n) +#define strlen(__s) __builtin_strlen(__s) + +#endif /* __STDC_HOSTED__ || __STDC_VERSION__ < C2x */ +#endif /* __CLANG_STRING_H */ + Index: clang/lib/Lex/ModuleMap.cpp =================================================================== --- clang/lib/Lex/ModuleMap.cpp +++ clang/lib/Lex/ModuleMap.cpp @@ -386,6 +386,7 @@ .Case("stdbool.h", true) .Case("stddef.h", true) .Case("stdint.h", true) + .Case("string.h", true) .Case("tgmath.h", true) .Case("unwind.h", true) .Default(false); Index: clang/test/C/C2x/n2524.c =================================================================== --- /dev/null +++ clang/test/C/C2x/n2524.c @@ -0,0 +1,100 @@ +// RUN: %clang_cc1 -std=c2x %s -ffreestanding -verify +// RUN: %clang_cc1 -std=c2x %s -ffreestanding -DCODEGEN -emit-llvm -o - | FileCheck %s + +/* WG14 N2524: partial + * String functions for freestanding implementations + * + * We have partial support, but are still missing builtin implementations for: + * memccpy + * memset_explicit + * strtok + * before we can claim full support. + */ + +#include + +/* Ensure that the version macro is defined to the value we expect. */ +#ifndef __STDC_VERSION_STRING_H__ +#error "expected __STDC_VERSION_STRING_H__ to be defined" +#elif __STDC_VERSION_STRING_H__ != 202300L /* FIXME: This should change to 202311L when ready */ +#error "expected __STDC_VERSION_STRING_H__ to be 202311L" +#endif + +/* Ensure that we emit the expected calls to a builtin function when using the + * various freestanding interfaces. + */ +void test(char *buffer1, char *buffer2, typeof(sizeof(0)) count, int n) { + memcpy(buffer1, buffer2, count); + // CHECK: call void @llvm.memcpy.p0.p0. + // FIXME memccpy(buffer1, buffer2, count, n); + memmove(buffer1, buffer2, count); + // CHECK: call void @llvm.memmove.p0.p0. + strcpy(buffer1, buffer2); + // CHECK: call ptr @strcpy + strncpy(buffer1, buffer2, count); + // CHECK: call ptr @strncpy + + strcat(buffer1, buffer2); + // CHECK: call ptr @strcat + strncat(buffer1, buffer2, count); + // CHECK: call ptr @strncat + + memcmp(buffer1, buffer2, count); + // CHECK: call i32 @memcmp + strcmp(buffer1, buffer2); + // CHECK: call i32 @strcmp + strncmp(buffer1, buffer2, count); + // CHECK: call i32 @strncmp + + memchr(buffer1, n, count); + // CHECK: call ptr @memchr + strchr(buffer1, n); + // CHECK: call ptr @strchr + strcspn(buffer1, buffer2); + // CHECK: call i{{32|64}} @strcspn + strpbrk(buffer1, buffer2); + // CHECK: call ptr @strpbrk + strrchr(buffer1, n); + // CHECK: call ptr @strrchr + strspn(buffer1, buffer2); + // CHECK: call i{{32|64}} @strspn + strstr(buffer1, buffer2); + // CHECK: call ptr @strstr + // FIXME: strtok(buffer1, buffer2); + + memset(buffer1, n, count); + // CHECK: call void @llvm.memset.p0 + // FIXME: memset_explicit(buffer1, n, count); + strlen(buffer1); + // CHECK: call i{{32|64}} @strlen +} + +/* Some functions take and return a QVoid * or QChar * because the interface + * is expected to work with both a pointer to a const-qualified type as well as + * a pointer to a non-const-qualified type. Ensure we get the correct type + * interfaces we expect. + * + * This is a feature of WG14 N3020 rather than N2524, but because Clang doesn't + * vend libc directly, the only way to test this is with the freestanding + * implementation we support. + * + * FIXME: this support needs to be implemented still. Once the support is added + * and these assertions pass, combine the RUN lines and drop -DCODEGEN. + */ +#ifndef CODEGEN +#define TEST(T, Expected) _Generic(T, Expected : 1, default : 0) +_Static_assert(TEST(memchr((void *)0, 0, 0), void *), ""); +_Static_assert(TEST(memchr((const void *)0, 0, 0), const void *), ""); // expected-error {{static assertion failed}} + +_Static_assert(TEST(strchr((char *)0, 0), char *), ""); +_Static_assert(TEST(strchr((const char *)0, 0), const char *), ""); // expected-error {{static assertion failed}} + +_Static_assert(TEST(strpbrk((char *)0, 0), char *), ""); +_Static_assert(TEST(strpbrk((const char *)0, 0), const char *), ""); // expected-error {{static assertion failed}} + +_Static_assert(TEST(strrchr((char *)0, 0), char *), ""); +_Static_assert(TEST(strrchr((const char *)0, 0), const char *), ""); // expected-error {{static assertion failed}} + +_Static_assert(TEST(strstr((char *)0, 0), char *), ""); +_Static_assert(TEST(strstr((const char *)0, 0), const char *), ""); // expected-error {{static assertion failed}} +#endif // CODEGEN Index: clang/www/c_status.html =================================================================== --- clang/www/c_status.html +++ clang/www/c_status.html @@ -840,7 +840,15 @@ String functions for freestanding implementations N2524 - No + +
Partial + Clang implements all of the freestanding functions from string.h + except memset_explicit, strtok, and + memccpy. Additionally, Clang is missing support for + WG14 N3020 that impacts some of the function return types based on + the signature used. +
+ Digit separators @@ -1159,6 +1167,11 @@ N2975 Clang 16 + + Qualifier-preserving standard library functions, v4 + N3020 + No + Enhanced enumerations N3030