Emit C attributes via cbindgen

This commit is contained in:
Josh Megnauth
2024-11-17 16:15:07 +00:00
committed by Jeremy Soller
parent a45c7b26d9
commit 5348273ccc
29 changed files with 175 additions and 35 deletions
+8
View File
@@ -14,3 +14,11 @@
# XXX: silences a warning
"feature = no_std" = "__relibc__"
# Ensure attributes are passed down from Rust
# <features.h> must be included where attributes are used in relibc
[fn]
must_use = "__nodiscard"
deprecated = "__deprecated"
deprecated_with_note = "__deprecatedNote({})"
no_return = "__noreturn"
+80 -14
View File
@@ -3,26 +3,92 @@
* Copyright (c) 2020 Rich Felker musl-libc
*/
#ifndef _FEATURES_H
#define _FEATURES_H
#ifndef _FEATURES_H__RELIBC
#define _FEATURES_H__RELIBC
#if __STDC_VERSION__ >= 199901L
#define __restrict restrict
#elif !defined(__GNUC__)
#define __restrict
// Version metadata for feature gating
// This is useful for divergent implementation specific behavior
// glibc, ulibc, and likely others define a similar macro
// musl does not define an equivalent macro
#define __RELIBC__ 1
#define __RELIBC__MAJOR 0
#define __RELIBC__MINOR 2
/*
* Sources:
* https://en.cppreference.com/w/c/language/attributes
* https://clang.llvm.org/docs/LanguageExtensions.html
* https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fc_005fattribute.html
* https://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html
*/
// Clang doesn't define __has_cpp_attribute if compiling C code
#if !defined(__has_cpp_attribute)
#define __has_cpp_attribute(x) 0
#endif
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
#define __inline inline
#elif !defined(__GNUC__)
#define __inline
// Clang doesn't define __has_c_attribute if compiling C++ code
#if !defined(__has_c_attribute)
#define __has_c_attribute(x) 0
#endif
#if __STDC_VERSION__ >= 201112L
#elif defined(__GNUC__)
#define _Noreturn __attribute__((__noreturn__))
// Check if C23+ attributes are available
#if defined(__cplusplus)
// HACK: GCC backports C++ attributes to C++98 but doesn't accept attributes
// placed before the function like cbindgen emits.
// Let's just disable attributes for C++98 by checking if a random C++11
// feature is available.
#define __HAS_ATTRIBUTE(x) __cpp_variable_templates &&__has_cpp_attribute(x)
#else
#define _Noreturn
#define __HAS_ATTRIBUTE(x) \
(__has_c_attribute(x) || __STDC_VERSION__ >= 202311L || \
__has_cpp_attribute(x))
#endif
// TODO: Not emitted with cbindgen
#if __STDC_VERSION__ >= 199901L
#define __restrict restrict
#elif !defined(__GNUC__)
#define __restrict
#endif
// TODO: Not emitted with cbindgen
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus)
#define __inline inline
#elif !defined(__GNUC__)
#define __inline
#endif
// Analogous to Rust's Never type
#if __HAS_ATTRIBUTE(noreturn)
#define __noreturn [[noreturn]]
// #elif __STDC_VERSION__ >= 201112L
// FIXME: cbindgen incorrectly places _Noreturn
// #define __noreturn _Noreturn
#elif defined(__GNUC__)
#define __noreturn __attribute__((__noreturn__))
#else
#define __noreturn
#endif
// Analogous to Rust's #[must_use]
// C23 only
#if __HAS_ATTRIBUTE(nodiscard)
#define __nodiscard [[nodiscard]]
#define __nodiscardNote(x) [[nodiscard(x)]]
#else
#define __nodiscard
#define __nodiscardNote(x)
#endif
// Analogous to Rust's #[deprecated]
// C23 only
#if __HAS_ATTRIBUTE(deprecated)
#define __deprecated [[deprecated]]
#define __deprecatedNote(x) [[deprecated(x)]]
#else
#define __deprecated
#define __deprecatedNote(x)
#endif
#endif
+1 -4
View File
@@ -1,4 +1,4 @@
sys_includes = []
sys_includes = ["features.h"]
include_guard = "_RELIBC_ASSERT_H"
trailer = "#include <bits/assert.h>"
language = "C"
@@ -8,6 +8,3 @@ cpp_compat = true
[enum]
prefix_with_name = true
[fn]
no_return = "__attribute__((noreturn))"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["bits/ctype.h"]
sys_includes = ["bits/ctype.h", "features.h"]
include_guard = "_RELIBC_CTYPE_H"
language = "C"
style = "Tag"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["sys/types.h"]
sys_includes = ["sys/types.h", "features.h"]
include_guard = "_RELIBC_DIRENT_H"
language = "C"
style = "Both"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["sys/socket.h", "netinet/in.h"]
sys_includes = ["sys/socket.h", "netinet/in.h", "features.h"]
include_guard = "_RELIBC_NETDB_H"
trailer = "#include <bits/netdb.h>"
language = "C"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["sched.h", "time.h", "bits/pthread.h"]
sys_includes = ["sched.h", "time.h", "bits/pthread.h", "features.h"]
include_guard = "_RELIBC_PTHREAD_H"
language = "C"
style = "tag"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["bits/signal.h", "stdint.h", "sys/types.h", "time.h", "bits/pthread.h"]
sys_includes = ["bits/signal.h", "stdint.h", "sys/types.h", "time.h", "bits/pthread.h", "features.h"]
include_guard = "_RELIBC_SIGNAL_H"
trailer = "#include <bits/signal.h>"
language = "C"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h", "features.h"]
include_guard = "_RELIBC_STDIO_H"
trailer = "#include <bits/stdio.h>"
language = "C"
+1 -4
View File
@@ -1,4 +1,4 @@
sys_includes = ["stddef.h", "alloca.h", "wchar.h"]
sys_includes = ["stddef.h", "alloca.h", "wchar.h", "features.h"]
include_guard = "_RELIBC_STDLIB_H"
trailer = "#include <bits/stdlib.h>"
language = "C"
@@ -8,6 +8,3 @@ cpp_compat = true
[enum]
prefix_with_name = true
[fn]
no_return = "__attribute__((noreturn))"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["sys/types.h"]
sys_includes = ["sys/types.h", "features.h"]
include_guard = "_SYS_TIME_H"
language = "C"
trailer = "#include <bits/sys/time.h>"
+1
View File
@@ -7,6 +7,7 @@ sys_includes = [
"stddef.h",
"sys/select.h",
"bits/pthread.h",
"features.h",
]
include_guard = "_SYS_TYPES_H"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["stdint.h"]
sys_includes = ["stdint.h", "features.h"]
include_guard = "_RELIBC_TERMIOS_H"
language = "C"
style = "Tag"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["sys/types.h", "stdint.h", "stddef.h"]
sys_includes = ["sys/types.h", "stdint.h", "stddef.h", "features.h"]
include_guard = "_RELIBC_TIME_H"
language = "C"
style = "Tag"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["stddef.h", "stdint.h", "sys/types.h"]
sys_includes = ["stddef.h", "stdint.h", "sys/types.h", "features.h"]
include_guard = "_RELIBC_UNISTD_H"
trailer = """
#include <bits/fcntl.h>
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["sys/types.h"]
sys_includes = ["sys/types.h", "features.h"]
include_guard = "_RELIBC_UTIME_H"
language = "C"
style = "Tag"
+1 -1
View File
@@ -1,4 +1,4 @@
sys_includes = ["stddef.h", "stdint.h", "stdio.h", "time.h", "bits/wchar.h"]
sys_includes = ["stddef.h", "stdint.h", "stdio.h", "time.h", "bits/wchar.h", "features.h"]
include_guard = "_RELIBC_WCHAR_H"
language = "C"
style = "Type"
+1
View File
@@ -19,6 +19,7 @@ EXPECT_NAMES=\
error \
fcntl/create \
fcntl/fcntl \
features \
fnmatch \
futimens \
libgen \
+3
View File
@@ -301,6 +301,8 @@ size_t num_test_cases = sizeof(test_cases) / sizeof(struct test_case);
int main(void) {
int retval = EXIT_SUCCESS;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
for(size_t i = 0; i < num_test_cases; ++i) {
struct test_case tc = test_cases[i];
CHECK_TEST(tc, isalnum, retval);
@@ -320,6 +322,7 @@ int main(void) {
CHECK_TEST(tc, tolower, retval);
CHECK_TEST(tc, toupper, retval);
}
#pragma GCC diagnostic pop
if (retval == EXIT_SUCCESS) {
printf("Success: %d\n", retval);
View File
View File
+39
View File
@@ -0,0 +1,39 @@
// These tests are primarily to ensure the macros compile without
// causing any funny business.
#include <features.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
__deprecated
static void legacy(void) {}
__deprecatedNote("Sometimes deletes user's home (oops); use foobar")
static void legacy_notes(void) {}
__nodiscard
static uint8_t the_answer(void) {
return 42;
}
// GCC bug
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"
__noreturn
static void foobar(void) {
exit(0);
}
#pragma GCC diagnostic pop
int main(void) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
legacy();
legacy_notes();
#pragma GCC diagnostic pop
const int answer = the_answer();
char buf[40] = {0};
sprintf(buf, "Hey, -Werror, I'm using answer: %d\n", answer);
foobar();
}
+3
View File
@@ -42,7 +42,10 @@ int main(void) {
exit(1);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
strncat(path, mktemp(temp), sizeof(temp));
#pragma GCC diagnostic pop
strncat(path, file, sizeof(file));
if (mkdir(temp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
fprintf(stderr, "mkdir %s: %s\n", temp, strerror(errno));
+4
View File
@@ -18,7 +18,11 @@ int main(void) {
exit(1);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
path = strncat(path, mktemp(temp), sizeof(temp));
#pragma GCC diagnostic pop
path = strncat(path, file, sizeof(file));
if (mkdir(temp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
fprintf(stderr, "mkdir %s: %s\n", temp, strerror(errno));
+3
View File
@@ -18,10 +18,13 @@ int main(void) {
exit(1);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if(!mktemp(temp)) {
fprintf(stderr, "Unable to create a unique dir name %s: %s\n", temp, strerror(errno));
exit(1);
}
#pragma GCC diagnostic pop
path = strncat(path, temp, strlen(temp));
path = strncat(path, file, strlen(file));
+3
View File
@@ -19,10 +19,13 @@ int main(void) {
exit(1);
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
if(!mktemp(temp)) {
fprintf(stderr, "Unable to create a unique dir name %s: %s\n", temp, strerror(errno));
exit(1);
}
#pragma GCC diagnostic pop
if (mkdir(temp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
fprintf(stderr, "mkdir %s: %s\n", temp, strerror(errno));
+2 -1
View File
@@ -21,6 +21,7 @@ EXPECT_NAMES=(\
error \
fcntl/create \
fcntl/fcntl \
features \
fnmatch \
futimens \
libgen \
@@ -205,4 +206,4 @@ STATUS_NAMES=(\
EXPECT_BINS=(${EXPECT_NAMES[@]/#/.\/bins_static\/})
STATUS_BINS=(${STATUS_NAMES[@]/#/-s.\/bins_static\/})
bins_verify/relibc-tests ${STATUS_BINS[@]} ${EXPECT_BINS[@]}
bins_verify/relibc-tests ${STATUS_BINS[@]} ${EXPECT_BINS[@]}
+11
View File
@@ -182,6 +182,9 @@ int main(void) {
test_cannot_alloc(ptr_reallocarray_maxsize, reallocarray_errno);
free(ptr_reallocarray_maxsize);
// Warning for deprecated functions is expected so silence -Werror
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
errno = 0;
char * ptr_memalign_size0 = (char *)memalign(aligned_alloc_alignment, zero_size);
int memalign_size0_errno = errno;
@@ -219,6 +222,8 @@ int main(void) {
printf("memalign (alignment 3): ");
test_invalid_aligned(ptr_memalign_align3, memalign_align3_errno);
free(ptr_memalign_align3);
#pragma GCC diagnostic pop
errno = 0;
char * ptr_aligned_alloc_goodsize = (char *)aligned_alloc(aligned_alloc_alignment, aligned_alloc_goodsize);
@@ -234,6 +239,10 @@ int main(void) {
test_invalid_aligned(ptr_aligned_alloc_badsize, aligned_alloc_badsize_errno);
free(ptr_aligned_alloc_badsize);
// Warning for deprecated functions is expected so silence -Werror
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
errno = 0;
char * ptr_valloc_size0 = (char *)valloc(zero_size);
int valloc_size0_errno = errno;
@@ -289,4 +298,6 @@ int main(void) {
printf("posix_memalign (SIZE_MAX): ");
test_cannot_alloc(ptr_posix_memalign_maxsize, posix_memalign_maxsize_return);
free(ptr_posix_memalign_maxsize);
#pragma GCC diagnostic pop
}
+3
View File
@@ -7,7 +7,10 @@
int main(void) {
char* string = (char*) calloc(20, sizeof(char));
strcpy(string, "tempXXXXXX");
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
mktemp(string);
#pragma GCC diagnostic pop
printf("%s\n",string);
free(string);
}