Emit C attributes via cbindgen
This commit is contained in:
committed by
Jeremy Soller
parent
a45c7b26d9
commit
5348273ccc
@@ -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
@@ -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 +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,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,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,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,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,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,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 +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,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>"
|
||||
|
||||
@@ -7,6 +7,7 @@ sys_includes = [
|
||||
"stddef.h",
|
||||
"sys/select.h",
|
||||
"bits/pthread.h",
|
||||
"features.h",
|
||||
]
|
||||
|
||||
include_guard = "_SYS_TYPES_H"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
sys_includes = ["stdint.h"]
|
||||
sys_includes = ["stdint.h", "features.h"]
|
||||
include_guard = "_RELIBC_TERMIOS_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
|
||||
@@ -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,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,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,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"
|
||||
|
||||
@@ -19,6 +19,7 @@ EXPECT_NAMES=\
|
||||
error \
|
||||
fcntl/create \
|
||||
fcntl/fcntl \
|
||||
features \
|
||||
fnmatch \
|
||||
futimens \
|
||||
libgen \
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
@@ -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[@]}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user