aaron.ballman created this revision. aaron.ballman added reviewers: clang-language-wg, jyknight, efriedma, joerg. Herald added a project: All. aaron.ballman requested review of this revision. Herald added a project: clang.
This implements most of the support for WG14 N2524 (https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2524.htm), which adds `<string.h>` to the list of headers required by a freestanding implementation. We do not currently have builtins for `memccpy`, `memset_explicit`, or `strtok`, so those APIs are not yet exposed via our freestanding `string.h`. Further, we do not yet implement WG14 N3020 which changes the return type for some of the interfaces in string.h. So this patch does not claim full support for string.h yet (it adds the `__STDC_VERSION_STRING_H__` macro but leaves its value as `202300L` instead of `202311L` as required by the standard). Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D144889 Files: clang/docs/ReleaseNotes.rst clang/lib/Headers/CMakeLists.txt clang/lib/Headers/string.h clang/lib/Lex/ModuleMap.cpp clang/test/C/C2x/n2524.c clang/www/c_status.html
Index: clang/www/c_status.html =================================================================== --- clang/www/c_status.html +++ clang/www/c_status.html @@ -840,7 +840,15 @@ <tr> <td>String functions for freestanding implementations</td> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2524.htm">N2524</a></td> - <td class="none" align="center">No</td> + <td class="partial" align="center"> + <details><summary>Partial</summary> + Clang implements all of the freestanding functions from string.h + except <code>memset_explicit</code>, <code>strtok</code>, and + <code>memccpy</code>. Additionally, Clang is missing support for + WG14 N3020 that impacts some of the function return types based on + the signature used. + </details> + </td> </tr> <tr> <td>Digit separators</td> @@ -1159,6 +1167,11 @@ <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2975.pdf">N2975</a></td> <td class="unreleased" align="center">Clang 16</td> </tr> + <tr> + <td>Qualifier-preserving standard library functions, v4</td> + <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3020.pdf">N3020</a></td> + <td class="none" align="center">No</td> + </tr> <tr> <td>Enhanced enumerations</td> <td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3030.htm">N3030</a></td> 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 <string.h> + +/* 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/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/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(<string.h>) +#include_next <string.h> +#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 <string.h> 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/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/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 ``<string.h>`` to the list of headers supported by freestanding + compilations. This partially implements + `WG14 N2524 <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2524.htm>`_, + 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 ``<string.h>``. + Non-comprehensive list of changes in this release ------------------------------------------------- - Clang now saves the address of ABI-indirect function parameters on the stack,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits