Skip to content

Commit 074555b

Browse files
authored
Merge pull request #3113 from geky/static-assert
Add static assert macro
2 parents 7eaf32b + c11ce21 commit 074555b

File tree

9 files changed

+246
-12
lines changed

9 files changed

+246
-12
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <stdio.h>
2+
#include <stdint.h>
3+
4+
#include "toolchain.h"
5+
#include "greentea-client/test_env.h"
6+
#include "unity.h"
7+
#include "utest.h"
8+
9+
using namespace utest::v1;
10+
11+
void no_test() {}
12+
13+
utest::v1::status_t test_setup(const size_t number_of_cases) {
14+
GREENTEA_SETUP(5, "default_auto");
15+
return verbose_test_setup_handler(number_of_cases);
16+
}
17+
18+
Case cases[] = {
19+
Case("Compilation test", no_test),
20+
};
21+
22+
Specification specification(test_setup, cases);
23+
24+
int main() {
25+
return !Harness::run(specification);
26+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#include "mbed_assert.h"
2+
#define THE_ANSWER 42
3+
4+
// Tests for static asserts in different contexts
5+
// multiple asserts are used to garuntee no conflicts occur in generated labels
6+
7+
// Test for static asserts in global context
8+
MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
9+
"An int must be larger than char");
10+
MBED_STATIC_ASSERT(2 + 2 == 4,
11+
"Hopefully the universe is mathematically consistent");
12+
MBED_STATIC_ASSERT(THE_ANSWER == 42,
13+
"Said Deep Thought, with infinite majesty and calm");
14+
15+
struct test {
16+
int dummy;
17+
18+
// Test for static asserts in struct context
19+
MBED_STRUCT_STATIC_ASSERT(sizeof(int) >= sizeof(char),
20+
"An int must be larger than char");
21+
MBED_STRUCT_STATIC_ASSERT(2 + 2 == 4,
22+
"Hopefully the universe is mathematically consistent");
23+
MBED_STRUCT_STATIC_ASSERT(THE_ANSWER == 42,
24+
"Said Deep Thought, with infinite majesty and calm");
25+
};
26+
27+
MBED_STATIC_ASSERT(sizeof(struct test) == sizeof(int),
28+
"Static assertions should not change the size of a struct");
29+
30+
void doit_c(void) {
31+
// Test for static asserts in function context
32+
MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
33+
"An int must be larger than char");
34+
MBED_STATIC_ASSERT(2 + 2 == 4,
35+
"Hopefully the universe is mathematically consistent");
36+
MBED_STATIC_ASSERT(THE_ANSWER == 42,
37+
"Said Deep Thought, with infinite majesty and calm");
38+
}
39+
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#include "mbed_assert.h"
2+
#define THE_ANSWER 42
3+
4+
// Tests for static asserts in different contexts
5+
// multiple asserts are used to garuntee no conflicts occur in generated labels
6+
7+
// Test for static asserts in global context
8+
MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
9+
"An int must be larger than char");
10+
MBED_STATIC_ASSERT(2 + 2 == 4,
11+
"Hopefully the universe is mathematically consistent");
12+
MBED_STATIC_ASSERT(THE_ANSWER == 42,
13+
"Said Deep Thought, with infinite majesty and calm");
14+
15+
struct test {
16+
int dummy;
17+
18+
// Test for static asserts in struct context
19+
MBED_STRUCT_STATIC_ASSERT(sizeof(int) >= sizeof(char),
20+
"An int must be larger than char");
21+
MBED_STRUCT_STATIC_ASSERT(2 + 2 == 4,
22+
"Hopefully the universe is mathematically consistent");
23+
MBED_STRUCT_STATIC_ASSERT(THE_ANSWER == 42,
24+
"Said Deep Thought, with infinite majesty and calm");
25+
26+
MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
27+
"An int must be larger than char");
28+
MBED_STATIC_ASSERT(2 + 2 == 4,
29+
"Hopefully the universe is mathematically consistent");
30+
MBED_STATIC_ASSERT(THE_ANSWER == 42,
31+
"Said Deep Thought, with infinite majesty and calm");
32+
};
33+
34+
MBED_STATIC_ASSERT(sizeof(struct test) == sizeof(int),
35+
"Static assertions should not change the size of a struct");
36+
37+
void doit_c(void) {
38+
// Test for static asserts in function context
39+
MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
40+
"An int must be larger than char");
41+
MBED_STATIC_ASSERT(2 + 2 == 4,
42+
"Hopefully the universe is mathematically consistent");
43+
MBED_STATIC_ASSERT(THE_ANSWER == 42,
44+
"Said Deep Thought, with infinite majesty and calm");
45+
}
46+

events/equeue/equeue_mbed.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,10 @@ static void equeue_tick_update() {
3838
}
3939

4040
static void equeue_tick_init() {
41-
MBED_ASSERT(sizeof(equeue_timer) >= sizeof(Timer));
42-
MBED_ASSERT(sizeof(equeue_ticker) >= sizeof(Ticker));
41+
MBED_STATIC_ASSERT(sizeof(equeue_timer) >= sizeof(Timer),
42+
"The equeue_timer buffer must fit the class Timer");
43+
MBED_STATIC_ASSERT(sizeof(equeue_ticker) >= sizeof(Ticker),
44+
"The equeue_ticker buffer must fit the class Ticker");
4345
new (equeue_timer) Timer;
4446
new (equeue_ticker) Ticker;
4547

@@ -78,7 +80,8 @@ void equeue_mutex_unlock(equeue_mutex_t *m) {
7880
#ifdef MBED_CONF_RTOS_PRESENT
7981

8082
int equeue_sema_create(equeue_sema_t *s) {
81-
MBED_ASSERT(sizeof(equeue_sema_t) >= sizeof(Semaphore));
83+
MBED_STATIC_ASSERT(sizeof(equeue_sema_t) >= sizeof(Semaphore),
84+
"The equeue_sema_t must fit the class Semaphore");
8285
new (s) Semaphore(0);
8386
return 0;
8487
}

features/netsocket/NetworkStack.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,8 @@ class NetworkStackWrapper : public NetworkStack
281281
// Conversion function for network stacks
282282
NetworkStack *nsapi_create_stack(nsapi_stack_t *stack)
283283
{
284-
MBED_ASSERT(sizeof stack->_stack_buffer >= sizeof(NetworkStackWrapper));
284+
MBED_STATIC_ASSERT(sizeof stack->_stack_buffer >= sizeof(NetworkStackWrapper),
285+
"The nsapi_stack_t stack buffer must fit a NetworkStackWrapper");
285286
return new (stack->_stack_buffer) NetworkStackWrapper;
286287
}
287288

platform/Callback.h

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,8 @@ class Callback<R()> {
715715
&Callback::function_dtor<F>,
716716
};
717717

718-
MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F));
718+
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
719+
"Type F must not exceed the size of the Callback class");
719720
new (this) F(f);
720721
_ops = &ops;
721722
}
@@ -1421,7 +1422,8 @@ class Callback<R(A0)> {
14211422
&Callback::function_dtor<F>,
14221423
};
14231424

1424-
MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F));
1425+
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
1426+
"Type F must not exceed the size of the Callback class");
14251427
new (this) F(f);
14261428
_ops = &ops;
14271429
}
@@ -2127,7 +2129,8 @@ class Callback<R(A0, A1)> {
21272129
&Callback::function_dtor<F>,
21282130
};
21292131

2130-
MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F));
2132+
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
2133+
"Type F must not exceed the size of the Callback class");
21312134
new (this) F(f);
21322135
_ops = &ops;
21332136
}
@@ -2833,7 +2836,8 @@ class Callback<R(A0, A1, A2)> {
28332836
&Callback::function_dtor<F>,
28342837
};
28352838

2836-
MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F));
2839+
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
2840+
"Type F must not exceed the size of the Callback class");
28372841
new (this) F(f);
28382842
_ops = &ops;
28392843
}
@@ -3539,7 +3543,8 @@ class Callback<R(A0, A1, A2, A3)> {
35393543
&Callback::function_dtor<F>,
35403544
};
35413545

3542-
MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F));
3546+
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
3547+
"Type F must not exceed the size of the Callback class");
35433548
new (this) F(f);
35443549
_ops = &ops;
35453550
}
@@ -4245,7 +4250,8 @@ class Callback<R(A0, A1, A2, A3, A4)> {
42454250
&Callback::function_dtor<F>,
42464251
};
42474252

4248-
MBED_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F));
4253+
MBED_STATIC_ASSERT(sizeof(Callback) - sizeof(_ops) >= sizeof(F),
4254+
"Type F must not exceed the size of the Callback class");
42494255
new (this) F(f);
42504256
_ops = &ops;
42514257
}

platform/mbed_assert.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#ifndef MBED_ASSERT_H
2020
#define MBED_ASSERT_H
2121

22+
#include "mbed_preprocessor.h"
23+
2224
#ifdef __cplusplus
2325
extern "C" {
2426
#endif
@@ -49,6 +51,63 @@ do { \
4951
} while (0)
5052
#endif
5153

54+
55+
/** MBED_STATIC_ASSERT
56+
* Declare compile-time assertions, results in compile-time error if condition is false
57+
*
58+
* The assertion acts as a declaration that can be placed at file scope, in a
59+
* code block (except after a label), or as a member of a C++ class/struct/union.
60+
*
61+
* @note
62+
* Use of MBED_STATIC_ASSERT as a member of a struct/union is limited:
63+
* - In C++, MBED_STATIC_ASSERT is valid in class/struct/union scope.
64+
* - In C, MBED_STATIC_ASSERT is not valid in struct/union scope, and
65+
* MBED_STRUCT_STATIC_ASSERT is provided as an alternative that is valid
66+
* in C and C++ class/struct/union scope.
67+
*
68+
* @code
69+
* MBED_STATIC_ASSERT(MBED_LIBRARY_VERSION >= 120,
70+
* "The mbed library must be at least version 120");
71+
*
72+
* int main() {
73+
* MBED_STATIC_ASSERT(sizeof(int) >= sizeof(char),
74+
* "An int must be larger than a char");
75+
* }
76+
* @endcode
77+
*/
78+
#if defined(__cplusplus) && (__cplusplus >= 201103L || __cpp_static_assert >= 200410L)
79+
#define MBED_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
80+
#elif !defined(__cplusplus) && __STDC_VERSION__ >= 201112L
81+
#define MBED_STATIC_ASSERT(expr, msg) _Static_assert(expr, msg)
82+
#elif defined(__cplusplus) && defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) \
83+
&& (__GNUC__*100 + __GNUC_MINOR__) > 403L
84+
#define MBED_STATIC_ASSERT(expr, msg) __extension__ static_assert(expr, msg)
85+
#elif !defined(__cplusplus) && defined(__GNUC__) && !defined(__CC_ARM) \
86+
&& (__GNUC__*100 + __GNUC_MINOR__) > 406L
87+
#define MBED_STATIC_ASSERT(expr, msg) __extension__ _Static_assert(expr, msg)
88+
#elif defined(__ICCARM__)
89+
#define MBED_STATIC_ASSERT(expr, msg) static_assert(expr, msg)
90+
#else
91+
#define MBED_STATIC_ASSERT(expr, msg) \
92+
enum {MBED_CONCAT(MBED_ASSERTION_AT_, __LINE__) = sizeof(char[(expr) ? 1 : -1])}
93+
#endif
94+
95+
/** MBED_STRUCT_STATIC_ASSERT
96+
* Declare compile-time assertions, results in compile-time error if condition is false
97+
*
98+
* Unlike MBED_STATIC_ASSERT, MBED_STRUCT_STATIC_ASSERT can and must be used
99+
* as a member of a C/C++ class/struct/union.
100+
*
101+
* @code
102+
* struct thing {
103+
* MBED_STATIC_ASSERT(2 + 2 == 4,
104+
* "Hopefully the universe is mathematically consistent");
105+
* };
106+
* @endcode
107+
*/
108+
#define MBED_STRUCT_STATIC_ASSERT(expr, msg) int : (expr) ? 0 : -1
109+
110+
52111
#endif
53112

54113
/** @}*/

platform/mbed_preprocessor.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/** \addtogroup platform */
2+
/** @{*/
3+
/* mbed Microcontroller Library
4+
* Copyright (c) 2006-2013 ARM Limited
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
#ifndef MBED_PREPROCESSOR_H
19+
#define MBED_PREPROCESSOR_H
20+
21+
22+
/** MBED_CONCAT
23+
* Concatenate tokens together
24+
*
25+
* @note
26+
* Expands tokens before concatenation
27+
*
28+
* @code
29+
* // Creates a unique label based on the line number
30+
* int MBED_CONCAT(UNIQUE_LABEL_, __LINE__) = 1;
31+
* @endcode
32+
*/
33+
#define MBED_CONCAT(a, b) MBED_CONCAT_(a, b)
34+
#define MBED_CONCAT_(a, b) a##b
35+
36+
/** MBED_STRINGIFY
37+
* Converts tokens into strings
38+
*
39+
* @note
40+
* Expands tokens before stringification
41+
*
42+
* @code
43+
* // Creates a string based on the parameters
44+
* const char *c = MBED_STRINGIFY(This is a ridiculous way to create a string)
45+
* @endcode
46+
*/
47+
#define MBED_STRINGIFY(a) MBED_STRINGIFY_(a)
48+
#define MBED_STRINGIFY_(a) #a
49+
50+
51+
#endif
52+
53+
/** @}*/

platform/toolchain.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#ifndef MBED_TOOLCHAIN_H
2020
#define MBED_TOOLCHAIN_H
2121

22+
#include "mbed_preprocessor.h"
23+
2224

2325
// Warning for unsupported compilers
2426
#if !defined(__GNUC__) /* GCC */ \
@@ -65,8 +67,7 @@
6567
*/
6668
#ifndef MBED_ALIGN
6769
#if defined(__ICCARM__)
68-
#define _MBED_ALIGN(N) _Pragma(#N)
69-
#define MBED_ALIGN(N) _MBED_ALIGN(data_alignment=N)
70+
#define MBED_ALIGN(N) _Pragma(MBED_STRINGIFY(data_alignment=N))
7071
#else
7172
#define MBED_ALIGN(N) __attribute__((aligned(N)))
7273
#endif

0 commit comments

Comments
 (0)