diff --git a/src/cpp.c b/src/cpp.c index ad60643f4646e719c37cebfda39103fa7a7cf33c..86961ef7b67fd57b6442165c613e390fb80e4d9a 100644 --- a/src/cpp.c +++ b/src/cpp.c @@ -1947,6 +1947,21 @@ static void insert_callback_define_no_args(struct cpp *this, *! as @expr{#pragma strict_types@} . */ +/*! @decl constant static_assert + *! + *! This define expands to the symbol @[_Static_assert]. + *! + *! It is the preferred way to perform static + *! (ie compile-time) assertions. + *! + *! @note + *! The macro can also be used to check for whether static assertions + *! are supported. + *! + *! @seealso + *! @[_Static_assert()] + */ + /*! @decl constant __PIKE__ *! *! This define is always true. @@ -2236,8 +2251,9 @@ void f_cpp(INT32 args) do_magic_define(&this,"__DATE__",insert_current_date_as_string); do_magic_define(&this,"__TIME__",insert_current_time_as_string); - /* This is from the 201x C standard. */ + /* These are from the 201x C standard. */ do_magic_define(&this,"_Pragma",insert_pragma)->args = 1; + simple_add_define(&this, "static_assert", "_Static_assert"); /* These are Pike extensions. */ do_magic_define(&this,"__DIR__",insert_current_dir_as_string); diff --git a/src/operators.c b/src/operators.c index 5b97ca415dc26a7bdd75572190e294ac27112efb..383b4b71030a8a6cacf515e93feac89d27045fd5 100644 --- a/src/operators.c +++ b/src/operators.c @@ -5475,6 +5475,54 @@ static int generate_sizeof(node *n) extern int generate_call_function(node *n); +/*! @decl void _Static_assert(int constant_expression, string constant_message) + *! + *! Perform a compile-time assertion check. + *! + *! If @[constant_expression] is false, a compiler error message + *! containing @[constant_message] will be generated. + *! + *! @note + *! Note that the function call compiles to the null statement, + *! and thus does not affect the run-time. + *! + *! @seealso + *! @[cpp::static_assert] + */ +static int generate__Static_assert(node *n) +{ + struct compilation *c = THIS_COMPILATION; + ptrdiff_t tmp; + node **expr = my_get_arg(&_CDR(n), 0); + node **msg = my_get_arg(&_CDR(n), 1); + if(!expr || !msg || count_args(CDR(n)) != 2) { + yyerror("Bad number of arguments to _Static_assert()."); + return 1; + } + tmp = eval_low(*msg, 0); + if (tmp < 1) { + yyerror("Argument 2 to _Static_assert() is not constant."); + return 1; + } + if (tmp > 1) pop_n_elems(tmp-1); + if (TYPEOF(Pike_sp[-1]) != T_STRING) { + yyerror("Bad argument 2 to _Static_assert(), expected string."); + return 1; + } + tmp = eval_low(*expr, 0); + if (tmp < 1) { + pop_stack(); + yyerror("Argument 1 to _Static_assert is not constant."); + return 1; + } + if (tmp > 1) pop_n_elems(tmp-1); + if (SAFE_IS_ZERO(Pike_sp-1)) { + my_yyerror("Assertion failed: %S", Pike_sp[-2].u.string); + } + pop_n_elems(2); + return 1; +} + /*! @class string_assignment */ @@ -5828,6 +5876,10 @@ multiset & mapping -> mapping /* function(mixed,mixed ...:mixed) */ ADD_EFUN2("call_function",f_call_function,tFuncV(tMix,tMix,tMix),OPT_SIDE_EFFECT | OPT_EXTERNAL_DEPEND,0,generate_call_function); + /* From the 201x C standard */ + ADD_EFUN2("_Static_assert", NULL, + tFunc(tInt tStr, tVoid), OPT_TRY_OPTIMIZE, + NULL, generate__Static_assert); start_new_program(); ADD_STORAGE(struct string_assignment_storage); diff --git a/src/testsuite.in b/src/testsuite.in index 581aa931f19ece995045fb2f274caf916143184b..b55158bc52bd5a4ce60fc7ba41a6bfbf0c840c1b 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -709,6 +709,9 @@ ignore_warning("Soft cast of scope(0,function(*)) to function is a noop.", [[ test_eq(typeof([function]`+), typeof(`+)) ]]) +test_compile_error([[ static_assert(0, "Fail."); ]]) +test_any([[ static_assert(1, "Ok."); ]], 0) + test_any([[ /* Detect bug in modify_shared_string(). *