P99
p99_block.h
Go to the documentation of this file.
1 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
2 /* */
3 /* Except for parts copied from previous work and as explicitly stated below, */
4 /* the authors and copyright holders for this work are as follows: */
5 /* (C) copyright 2010-2014, 2018 Jens Gustedt, INRIA, France */
6 /* (C) copyright 2012 William Morris */
7 /* */
8 /* This file is free software; it is part of the P99 project. */
9 /* */
10 /* Licensed under the Apache License, Version 2.0 (the "License"); */
11 /* you may not use this file except in compliance with the License. */
12 /* You may obtain a copy of the License at */
13 /* */
14 /* http://www.apache.org/licenses/LICENSE-2.0 */
15 /* */
16 /* Unless required by applicable law or agreed to in writing, software */
17 /* distributed under the License is distributed on an "AS IS" BASIS, */
18 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
19 /* See the License for the specific language governing permissions and */
20 /* limitations under the License. */
21 /* */
22 #ifndef P99_BLOCK_H_
23 # define P99_BLOCK_H_
24 
25 #include "p99_int.h"
26 
42 #ifndef P00_DOXYGEN
43 #define P00_ROBUST(...) __VA_ARGS__
44 
45 #define P00 P99_FILEID(blk)
46 
47 #define P00_BLK_GEN(BEFORE, COND, ...) for (P00_ROBUST(BEFORE); (COND) && P00; (__VA_ARGS__), P00 = 0)
48 #define P00_BLK_BEFORE(...) for (__VA_ARGS__; P00; P00 = 0)
49 #define P00_BLK_AFTER(...) P00_BLK_BEFAFT(, (__VA_ARGS__))
50 #define P00_BLK_CONDITIONAL(...) for (; (__VA_ARGS__) && P00; P00 = 0)
51 #define P00_BLK_START P00_BLK_BEFORE(_Bool P00 = 1)
52 #define P00_BLK_END P00_BLK_BEFORE()
53 
54 /* The idea of this macro is that it evaluates INIT before the
55  declaration of NAME. Therefore we may then push a variable on the
56  stack with the same name as a variable of an enclosing scope, and
57  use its value of inside the expression. */
58 #define P00_BLK_DECL_REC(TYPE, NAME, ...) \
59 P00_BLK_BEFORE(TYPE P99_PASTE2(p00_decl_, NAME) = P00_ROBUST(__VA_ARGS__)) \
60 P00_BLK_BEFAFT(TYPE NAME = P99_PASTE2(p00_decl_, NAME), (void)NAME)
61 
62 /* If no initializer is given, the variable is initialized by
63  default. */
64 #define P00_BLK_DECL(...) \
65 P99_IF_EQ_2(P99_NARG(__VA_ARGS__)) \
66 (P00_BLK_DECL_2(__VA_ARGS__)) \
67 (P00_BLK_DECL_3(__VA_ARGS__))
68 
69 #define P00_BLK_DECL_3(TYPE, NAME, ...) P00_BLK_BEFAFT(TYPE NAME = __VA_ARGS__, (void)NAME)
70 
71 #define P00_BLK_DECL_2(TYPE, NAME) P00_BLK_DECL_3(TYPE, NAME, P99_INIT)
72 
73 /* Declare @a NAME to be a pointer to a static variable of type @a
74  * TYPE for the depending block. */
75 #define P00_BLK_DECL_STATIC(TYPE, NAME, ...) \
76 P00_BLK_DECL_STATIC4(TYPE, NAME, P99_UNIQ(p00_static, NAME), P00_ROBUST(__VA_ARGS__))
77 
78 #define P00_BLK_DECL_STATIC4(TYPE, NAME, ID, INIT) \
79 P00_BLK_BEFORE(TYPE* NAME = 0) \
80 P99_PREFER( \
81  static TYPE ID = INIT; \
82  NAME = &ID; \
83  goto ID; ) ID:
84 
85 #endif
86 
87 
92 #ifdef __GNUC__
93 # define P99_MARK(X) ({ __asm__ volatile ("# " P99_STRINGIFY(__LINE__: X)); })
94 #else
95 # define P99_MARK(X) P99_NOP
96 #endif
97 
103 #define P99_BLK_MARK(X) \
104 P00_BLK_BEFAFT(P99_MARK(P99_PASTE2(X, _bef)), \
105  P99_MARK(P99_PASTE2(X, _end)))
106 
107 
108 
109 
110 #define P00_UNWIND_DOCUMENT \
111 
118 #define P00_INHIBIT(NAME, EXT) P99_PASTE3(p00_inhibit_, NAME, EXT)
119 
120 
130 #define P99_DECLARE_INHIBIT(NAME) enum { P00_INHIBIT(NAME,) = 0 }
131 
137 #define P99_INHIBIT_CHECK(NAME) \
138 switch (P99_STRINGIFY(P00_INHIBIT(NAME,))[P00_INHIBIT(NAME,)]) default:
139 
140 
147 #define P99_INHIBIT(NAME) \
148 P00_BLK_START \
149 for (unsigned const*const P00_INHIBIT(NAME,) = 0; !P00_INHIBIT(NAME,) && P00; P00 = 0)
150 
151 
158 #define P99_ALLOW(NAME) \
159 P00_BLK_START \
160 P00_BLK_DECL(unsigned const, P00_INHIBIT(NAME,), 0)
161 
162 
163 P99_DECLARE_INHIBIT(RETURN);
164 
165 #if defined(P99_CHECK_RETURN) && !defined(P00_DOXYGEN)
166 #define return P99_INHIBIT_CHECK(RETURN) return
167 #endif
168 
169 #ifdef P00_DOXYGEN
170 
178 #define P99_CHECK_RETURN
179 #endif
180 
185 #define P00_BLK_BEFAFT(BEFORE, ...) \
186 P99_INHIBIT(RETURN) \
187 P00_BLK_GEN(P00_ROBUST(BEFORE), true, __VA_ARGS__)
188 
189 #ifdef P00_DOXYGEN
190 
217 #define P99_PROTECTED_BLOCK(BEFORE, AFTER)
218 #else
219 #define P99_PROTECTED_BLOCK(BEFORE, ...) \
220 P00_BLK_START \
221 P00_BLK_BEFAFT(P00_ROBUST(BEFORE), __VA_ARGS__) \
222 /* Ensure that a `break' will still execute AFTER */ \
223 P00_BLK_END
224 #endif
225 
226 # ifndef P99_SIMPLE_BLOCKS
227 
240 # define P99_SIMPLE_BLOCKS 0
241 # endif
242 
243 #ifdef P00_DOXYGEN
244 
268 P00_UNWIND_DOCUMENT
269 #define P99_GUARDED_BLOCK(T, NAME, INITIAL, BEFORE, AFTER)
270 #else
271 # if !P99_SIMPLE_BLOCKS
272 P00_DOCUMENT_WARN_VLA_ARGUMENT(P99_GUARDED_BLOCK, 0)
273 P00_DOCUMENT_DECLARATION_ARGUMENT(P99_GUARDED_BLOCK, 1)
274 P00_DOCUMENT_STATEMENT_ARGUMENT(P99_GUARDED_BLOCK, 4)
275 # define P99_GUARDED_BLOCK(T, NAME, INITIAL, BEFORE, AFTER) \
276 P00_BLK_START \
277 P00_BLK_DECL_REC(T, NAME, P00_ROBUST(INITIAL)) \
278 P99_UNWIND_PROTECT if (0) { P99_PROTECT: AFTER; } else \
279 P00_BLK_BEFAFT(P00_ROBUST(BEFORE), AFTER) \
280 /* Ensure that a `break' will still execute AFTER */ \
281 P00_BLK_END
282 # else
283 # define P99_GUARDED_BLOCK(T, NAME, INITIAL, BEFORE, AFTER) \
284 P00_BLK_START \
285 P00_BLK_DECL(T, NAME, P00_ROBUST(INITIAL)) \
286 P00_BLK_BEFAFT(P00_ROBUST(BEFORE), AFTER) \
287 /* Ensure that a `break' will still execute AFTER */ \
288 P00_BLK_END
289 # endif
290 #endif
291 
297 #define P99_NOP ((void)0)
298 
326 #if p99_has_feature(statement_expression)
327 # define P99_PREFER(...) /* avoid the dangling else problem */ \
328 for (_Bool p00 = 1; p00 && p99_extension ({ { __VA_ARGS__ } 1; }); p00 = 0)
329 #else
330 # define P99_PREFER(...) if (1) { __VA_ARGS__ } else
331 #endif
332 
360 #define P99_AVOID for (;0;)
361 
387 #define P99_BLOCK(...) P99_PREFER(__VA_ARGS__) P99_NOP
388 
424 #define P99_XCASE P99_AVOID case
425 
429 #define P99_XDEFAULT P99_AVOID default
430 
431 typedef enum p00_uncase_enum {
432  p00_uncase = 0,
433 } p00_uncase_enum;
434 
435 
436 #define P00_UNCASE switch((p00_uncase_enum)0) P99_XCASE 0
437 
445 #define P99_UNCASE P00_UNCASE :
446 
472 #define P99_HANDLE_ERRNO \
473 P00_BLK_START \
474 P00_BLK_DECL(int const, p99_errno, errno) \
475  switch (P99_UNLIKELY(!!p99_errno)) case true: \
476  P00_BLK_AFTER(errno = 0) \
477  switch (p99_errno) case 0:
478 
479 
480 enum p99_unwind {
487  p99_unwind_level = 0,
488  p00_unwind_top = 0,
489  p00_unwind_prev = 0,
490  p00_unwind_bottom = 0,
491  p99_unwind_return = INT_MAX,
492 };
493 
506 #define p99_unwind_code ((int)(p00_unwind_top[0].p00_code))
507 
508 
509 P99_DECLARE_STRUCT(p00_jmp_buf0);
510 
511 struct p00_jmp_buf0 {
512  p00_jmp_buf0 * p99_lifo;
513  bool volatile p00_returning;
514  int volatile p00_code;
515  jmp_buf p00_buf;
516 };
517 
518 #define P00_JMP_BUF0_INITIALIZER { .p00_returning = 0 /* initialize .p00_buf implicitly */ }
519 
520 typedef p00_jmp_buf0 p00_jmp_buf[1];
521 
522 #define P00_JMP_BUF_INITIALIZER { [0] = P00_JMP_BUF0_INITIALIZER }
523 
524 P99_DECLARE_STRUCT(p00_inhibitor);
525 
526 struct p00_inhibitor {
527  int p00_a;
528 };
529 
531 noreturn
532 void p00_longjmp(p00_jmp_buf0 * p00_buf, int p00_val) {
533  p00_buf->p00_code = p00_val;
534  longjmp(p00_buf->p00_buf, 1);
535 }
536 
613 #define P99_UNWIND_PROTECT \
614 P00_BLK_START \
615 /* The jump buffer for the case that P99_UNWIND_RETURN is launched \
616  inside this construct. Only the lowest level variable will be \
617  needed but since we don't know our level yet, we have to declare \
618  this at every level. */ \
619 P00_BLK_BEFAFT(auto p00_jmp_buf p00_unwind_return = P00_ROBUST(P00_JMP_BUF_INITIALIZER), \
620  /* returning can only be on because it was set by \
621  P99_UNWIND_RETURN and we fell of the edge after all \
622  P99_PROTECT clauses */ \
623  p00_unwind_return[0].p00_returning ? p00_longjmp(p00_unwind_return, 1) : P99_NOP) \
624 /* Detect the bottom of enclosing other P99_UNWIND_PROTECT. If it \
625  exists set it to that one, otherwise set it to our newly allocated \
626  jump buffer. We have to do this in two steps such that the \
627  initializer of the variable is not the variable itself. */ \
628 P00_BLK_DECL_REC(register p00_jmp_buf *const, p00_unwind_bottom, \
629  (p00_unwind_bottom ? p00_unwind_bottom : &p00_unwind_return)) \
630  /* inhibit further access of the p00_unwind_return variable */ \
631  P00_BLK_DECL(register p00_inhibitor const, p00_unwind_return, { INT_MAX }) \
632 /* are we unwinding or not? */ \
633  P00_BLK_DECL(auto _Bool volatile, p00_unw) \
634 /* The return code from the longjmp to which we apply the \
635  special convention concerning the value 0. */ \
636  P00_BLK_BEFAFT(auto int volatile p00_code = 0, \
637  /* An eventual continuation of the unwind process is \
638  decided here, since here the p00_unwind_top \
639  variable that is visible is that of the enclosing \
640  scope, but the unwind code variable is ours. If \
641  the enclosing scope is the outer scope, \
642  p00_unwind_top is a integer with value zero. So \
643  even then the P99_UNWIND is syntactically correct, \
644  but fortunately the underlying call to longjmp \
645  will not be issued. */ \
646  (p00_unw \
647  ? P99_UNWIND(p00_code < 0 ? p00_code : p00_code - 1) \
648  : P99_NOP)) \
649 /* maintain the level of nesting of different calls to \
650  P99_UNWIND_PROTECT */ \
651  P00_BLK_DECL_REC(register unsigned const, p99_unwind_level, p99_unwind_level + 1) \
652  P00_BLK_DECL(p00_jmp_buf0*, p00_unwind_prev, p00_unwind_top) \
653 /* the buffer variable for setjmp/longjump */ \
654  P00_BLK_DECL(auto p00_jmp_buf, p00_unwind_top, P00_JMP_BUF_INITIALIZER) \
655  P00_BLK_END \
656 /* force interpretation of the setjmp return to 0 or 1, and ensure \
657  that it occurs in a context where it is permitted. */ \
658  switch (!setjmp(p00_unwind_top[0].p00_buf)) case 1:
659 
661 void p00_unwind(void* p00_top, unsigned p00_level, int p00_cond) {
662  if (p00_level && p00_cond && p00_top) p00_longjmp(p00_top, p00_cond);
663 }
664 
675 P00_UNWIND_DOCUMENT
676 /* This uses a very special trick, such that this a valid call to
677  longjmp at the end. On the lowest level p00_unwind_top is an
678  integer of value 0 that converts to a void* that can be passed to
679  longjmp as a formal parameter just such that the syntax is
680  correct. On higher recursion levels this will be the variable of
681  type jmp_buf that sits on the stack. jmp_buf is guaranteed to be an
682  array type, so the expression here evaluates to a pointer that then
683  is passed to the function. */
684 #define P99_UNWIND(X) p00_unwind(p00_unwind_top, p99_unwind_level, (X))
685 
710 P00_UNWIND_DOCUMENT
711 #define P99_UNWIND_RETURN \
712 /* we use a special form of short circuit evaluation here, since \
713  setjmp is only allowed in restricted contexts */ \
714 switch (!!p00_unwind_bottom) \
715  case 1: \
716  /* If an unwind is possible, i.e if we are not in the outer frame \
717  this will stop the evaluation of the expression here, and unwind \
718  as side effect. Otherwise, this will continue normally and \
719  directly proceed with the return. */ \
720  if (!setjmp(p00_unwind_bottom[0]->p00_buf)) { \
721  /* assign before we unwind all the way down */ \
722  p00_unwind_bottom[0]->p00_returning = 1; \
723  P99_UNWIND(-p99_unwind_return); \
724  } else case 0: P99_ALLOW(RETURN) return
725 
742 P00_UNWIND_DOCUMENT
743 #define P99_PROTECT \
744 P99_DECLARE_INHIBIT(RETURN); \
745  if (0) { \
746  case 0 : \
747  p00_code = p00_unwind_top[0].p00_code; \
748  p00_unw = !!p00_code; \
749  } \
750  P00_UNCASE
751 
756 #define P99_BLOCK_DOCUMENT \
757  \
758  \
759 
766 P00_DOCUMENT_MULTIPLE_ARGUMENT(P99_INVARIANT, 0)
768 #define P99_INVARIANT(EXPR) \
769 P99_PROTECTED_BLOCK(assert((EXPR) && "failed at beginning of block"), assert((EXPR) && "failed at end of block"))
770 
771 
776 /* Disable bogus warnings that are provoked by the code in this file. */
777 
778 P99_IF_COMPILER(INTEL, warning(disable: 589)) /* transfer of control bypasses initialization of... */
779 
780 
781 #endif /* !P99_BLOCK_H_ */
p99_unwind_return
@ p99_unwind_return
Definition: p99_block.h:490
P99_BLOCK_DOCUMENT
#define P99_BLOCK_DOCUMENT
Add some default documentation and links to the following block macro.
Definition: p99_block.h:732
noreturn
#define noreturn
Declare a function that doesn't return to the caller.
Definition: p99_compiler.h:842
p99_inline
#define p99_inline
Try to force a function always to be inlined.
Definition: p99_compiler.h:496
P99_GUARDED_BLOCK
#define P99_GUARDED_BLOCK(T, NAME, INITIAL, BEFORE, AFTER)
A meta-macro to protect a dependent block or statement by a guard variable NAME of type T.
Definition: p99_block.h:269
P99_DECLARE_INHIBIT
#define P99_DECLARE_INHIBIT(NAME)
Declare a feature NAME that can be inhibited or allowed at compile time in certain parts of code.
Definition: p99_block.h:130
P99_DECLARE_STRUCT
#define P99_DECLARE_STRUCT(NAME)
forward declaration of a struct NAME
Definition: p99_type.h:59
p99_unwind_level
@ p99_unwind_level
The level of nesting P99_UNWIND_PROTECT.
Definition: p99_block.h:486
longjmp
#define longjmp(...)
Default arguments for C99 function longjmp
Definition: p99_c99_default.h:55
P99_IF_COMPILER
#define P99_IF_COMPILER(COMP,...)
Issue the pragma that is given as a supplementary argument iff the actual compiler is COMP.
Definition: p99_compiler.h:1065
p99_unwind
p99_unwind
Definition: p99_block.h:479
p99_int.h
Macros handling integer types and initialization.