Merge pull request #97 from geky/compiler-polyfill

Add useful attributes supported by supported compilers
Sam Grove 2016-05-20 16:16:23 -05:00
commit 23d77e4423
4 changed files with 406 additions and 7 deletions

View File

@ -0,0 +1,134 @@
#include "toolchain.h"
#include <stdio.h>
#include <stdint.h>
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();
}

View File

@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdint.h>
#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 <int (*F)()>
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<testPacked>),
Case("Testing ALIGN attribute", test_wrapper<testAlign>),
Case("Testing UNUSED attribute", test_wrapper<testUnused>),
Case("Testing WEAK attribute", test_wrapper<testWeak>),
Case("Testing PURE attribute", test_wrapper<testPure>),
Case("Testing FORCEINLINE attribute", test_wrapper<testForceInline>),
Case("Testing NORETURN attribute", test_wrapper<testNoReturn>),
Case("Testing UNREACHABLE attribute", test_wrapper<testUnreachable>),
Case("Testing DEPRECATED attribute", test_wrapper<testDeprecated>),
};
Specification specification(test_setup, cases);
int main() {
return !Harness::run(specification);
}

View File

@ -0,0 +1,10 @@
#include "toolchain.h"
int testWeak1() {
return 0;
}
WEAK int testWeak2() {
return 1;
}

View File

@ -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 <rt_sys.h>
#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