diff --git a/hal/TESTS/api/toolchain/attributes.c b/hal/TESTS/api/toolchain/attributes.c new file mode 100644 index 0000000000..196d968c1c --- /dev/null +++ b/hal/TESTS/api/toolchain/attributes.c @@ -0,0 +1,134 @@ +#include "toolchain.h" + +#include +#include + + +typedef struct { + char a; + int x; +} PACKED TestAttrPackedStruct; + +int testPacked() { + int failed = 0; + + if (sizeof(TestAttrPackedStruct) != sizeof(int) + sizeof(char)) { + failed++; + } + + return failed; +} + + +int testAlign() { + int failed = 0; + + ALIGN(8) char a; + ALIGN(8) char b; + ALIGN(16) char c; + ALIGN(8) char d; + ALIGN(16) char e; + + if(((uintptr_t)&a) & 0x7){ + failed++; + } + if(((uintptr_t)&b) & 0x7){ + failed++; + } + if(((uintptr_t)&c) & 0xf){ + failed++; + } + if(((uintptr_t)&d) & 0x7){ + failed++; + } + if(((uintptr_t)&e) & 0xf){ + failed++; + } + + return failed; +} + + +int testUnused1(UNUSED int arg) { + return 0; +} + +int testUnused() { + return testUnused1(0); +} + + +int testWeak1(); +int testWeak2(); + +WEAK int testWeak1() { + return 1; +} + +int testWeak2() { + return 0; +} + +int testWeak() { + return testWeak1() | testWeak2(); +} + + +PURE int testPure1() { + return 0; +} + +int testPure() { + return testPure1(); +} + + +FORCEINLINE int testForceInline1() { + return 0; +} + +int testForceInline() { + return testForceInline1(); +} + + +NORETURN int testNoReturn1() { + while (1) {} +} + +int testNoReturn() { + if (0) { + testNoReturn1(); + } + return 0; +} + + +int testUnreachable1(int i) { + switch (i) { + case 0: + return 0; + } + + UNREACHABLE; +} + +int testUnreachable() { + return testUnreachable1(0); +} + + +DEPRECATED("this message should not be displayed") +void testDeprecatedUnused(); +void testDeprecatedUnused() { } + +DEPRECATED("this message should be displayed") +int testDeprecatedUsed(); +int testDeprecatedUsed() { + return 0; +} + +int testDeprecated() { + return testDeprecatedUsed(); +} + diff --git a/hal/TESTS/api/toolchain/main.cpp b/hal/TESTS/api/toolchain/main.cpp new file mode 100644 index 0000000000..4d64b2b2d4 --- /dev/null +++ b/hal/TESTS/api/toolchain/main.cpp @@ -0,0 +1,53 @@ +#include +#include + +#include "toolchain.h" +#include "test_env.h" +#include "unity.h" +#include "utest.h" + +using namespace utest::v1; + + +// Test functions declared as C functions to avoid issues with name mangling +extern "C" { + int testPacked(); + int testAlign(); + int testUnused(); + int testWeak(); + int testPure(); + int testForceInline(); + int testNoReturn(); + int testUnreachable(); + int testDeprecated(); +} + + +// Test wrapper and test cases for utest +template +void test_wrapper() { + TEST_ASSERT_UNLESS(F()); +} + +status_t test_setup(const size_t number_of_cases) { + GREENTEA_SETUP(40, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Testing PACKED attribute", test_wrapper), + Case("Testing ALIGN attribute", test_wrapper), + Case("Testing UNUSED attribute", test_wrapper), + Case("Testing WEAK attribute", test_wrapper), + Case("Testing PURE attribute", test_wrapper), + Case("Testing FORCEINLINE attribute", test_wrapper), + Case("Testing NORETURN attribute", test_wrapper), + Case("Testing UNREACHABLE attribute", test_wrapper), + Case("Testing DEPRECATED attribute", test_wrapper), +}; + +Specification specification(test_setup, cases); + +int main() { + return !Harness::run(specification); +} diff --git a/hal/TESTS/api/toolchain/weak.c b/hal/TESTS/api/toolchain/weak.c new file mode 100644 index 0000000000..d81125573f --- /dev/null +++ b/hal/TESTS/api/toolchain/weak.c @@ -0,0 +1,10 @@ +#include "toolchain.h" + +int testWeak1() { + return 0; +} + +WEAK int testWeak2() { + return 1; +} + diff --git a/hal/api/toolchain.h b/hal/api/toolchain.h index 7a79226941..b8756d206c 100644 --- a/hal/api/toolchain.h +++ b/hal/api/toolchain.h @@ -16,6 +16,214 @@ #ifndef MBED_TOOLCHAIN_H #define MBED_TOOLCHAIN_H + +// Warning for unsupported compilers +#if !defined(__GNUC__) /* GCC */ \ + && !defined(__CC_ARM) /* ARMCC */ \ + && !defined(__clang__) /* LLVM/Clang */ \ + && !defined(__ICCARM__) /* IAR */ +#warning "This compiler is not yet supported." +#endif + + +// Attributes + +/** PACKED + * Pack a structure, preventing any padding from being added between fields. + * + * @code + * #include "toolchain.h" + * + * typedef struct { + * char x; + * int y; + * } PACKED foo; + * @endcode + */ +#ifndef PACKED +#if defined(__ICCARM__) +#define PACKED __packed +#else +#define PACKED __attribute__((packed)) +#endif +#endif + +/** ALIGN(N) + * Declare a variable to be aligned on an N-byte boundary. + * + * @code + * #include "toolchain.h" + * + * ALIGN(16) char a; + * @endcode + */ +#ifndef ALIGN +#if defined(__ICCARM__) +#define _ALIGN(N) _Pragma(#N) +#define ALIGN(N) _ALIGN(data_alignment=N) +#else +#define ALIGN(N) __attribute__((aligned(N))) +#endif +#endif + +/** UNUSED + * Declare a function argument to be unused, suppressing compiler warnings + * + * @code + * #include "toolchain.h" + * + * void foo(UNUSED int arg) { + * + * } + * @endcode + */ +#ifndef UNUSED +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define UNUSED __attribute__((__unused__)) +#else +#define UNUSED +#endif +#endif + +/** WEAK + * Mark a function as being weak. + * + * @note + * weak functions are not friendly to making code re-usable, as they can only + * be overridden once (and if they are multiply overridden the linker will emit + * no warning). You should not normally use weak symbols as part of the API to + * re-usable modules. + * + * @code + * #include "toolchain.h" + * + * WEAK void foo() { + * // a weak implementation of foo that can be overriden by a definition + * // without __weak + * } + * @endcode + */ +#ifndef WEAK +#if defined(__ICCARM__) +#define WEAK __weak +#else +#define WEAK __attribute__((weak)) +#endif +#endif + +/** PURE + * Hint to the compiler that a function depends only on parameters + * + * @code + * #include "toolchain.h" + * + * PURE int foo(int arg){ + * // no access to global variables + * } + * @endcode + */ +#ifndef PURE +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define PURE __attribute__((const)) +#else +#define PURE +#endif +#endif + +/** FORCEINLINE + * Declare a function that must always be inlined. Failure to inline + * such a function will result in an error. + * + * @code + * #include "toolchain.h" + * + * FORCEINLINE void foo() { + * + * } + * @endcode + */ +#ifndef FORCEINLINE +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define FORCEINLINE static inline __attribute__((always_inline)) +#elif defined(__ICCARM__) +#define FORCEINLINE _Pragma("inline=force") static +#else +#define FORCEINLINE static inline +#endif +#endif + +/** NORETURN + * Declare a function that will never return. + * + * @code + * #include "toolchain.h" + * + * NORETURN void foo() { + * // must never return + * while (1) {} + * } + * @endcode + */ +#ifndef NORETURN +#if defined(__GNUC__) || defined(__clang__) || defined(__CC_ARM) +#define NORETURN __attribute__((noreturn)) +#elif defined(__ICCARM__) +#define NORETURN __noreturn +#else +#define NORETURN +#endif +#endif + +/** UNREACHABLE + * An unreachable statement. If the statement is reached, + * behaviour is undefined. Useful in situations where the compiler + * cannot deduce the unreachability of code. + * + * @code + * #include "toolchain.h" + * + * void foo(int arg) { + * switch (arg) { + * case 1: return 1; + * case 2: return 2; + * ... + * } + * UNREACHABLE; + * } + * @endcode + */ +#ifndef UNREACHABLE +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__CC_ARM) +#define UNREACHABLE __builtin_unreachable() +#else +#define UNREACHABLE while (1) +#endif +#endif + +/** DEPRECATED("message string") + * Mark a function declaration as deprecated, if it used then a warning will be + * issued by the compiler possibly including the provided message. Note that not + * all compilers are able to display the message. + * + * @code + * #include "toolchain.h" + * + * DEPRECATED("don't foo any more, bar instead") + * void foo(int arg); + * @endcode + */ +#ifndef DEPRECATED +#if defined(__GNUC__) || defined(__clang__) +#define DEPRECATED(M) __attribute__((deprecated(M))) +#elif defined(__CC_ARM) +#define DEPRECATED(M) __attribute__((deprecated)) +#else +#define DEPRECATED(M) +#endif +#endif + + +// FILEHANDLE declaration #if defined(TOOLCHAIN_ARM) #include #endif @@ -24,16 +232,10 @@ typedef int FILEHANDLE; #endif +// Backwards compatibility #ifndef EXTERN #define EXTERN extern #endif -#if defined (__ICCARM__) -# define WEAK __weak -# define PACKED __packed -#else -# define WEAK __attribute__((weak)) -# define PACKED __attribute__((packed)) -#endif #endif