1 /* Jitter: general-purpose CPP macros for stringification and concatenation. 2 3 Copyright (C) 2017, 2021 Luca Saiu 4 Updated in 2019 by Luca Saiu 5 Written by Luca Saiu 6 7 This file is part of Jitter. 8 9 Jitter is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Jitter is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */ 21 22 23 #ifndef JITTER_CPP_H_ 24 #define JITTER_CPP_H_ 25 26 /* This entire header has no dependencies and expands to nothing, by design. It 27 is safe to include from assembly sources. */ 28 29 /* Remark on multiple-level expansion. 30 * ************************************************************************** */ 31 32 /* Yes, these two-levels of macros are needed; see the (excellent) GNU CPP 33 manual. The resulting clumsiness is the real reason why the macros in this 34 header are useful. */ 35 36 37 38 39 /* Convenient stringification. 40 * ************************************************************************** */ 41 42 /* Expand to the stringification of the macro parameter, itself unexpanded. 43 This is not intended for the user. */ 44 #define JITTER_STRINGIFY_UNEXPANDED(whatever) \ 45 # whatever 46 47 /* Expand to the stringification of the macro parameter, after it is expanded 48 itself. */ 49 #define JITTER_STRINGIFY(whatever) \ 50 JITTER_STRINGIFY_UNEXPANDED(whatever) 51 52 53 54 55 /* Convenient token concatenation. 56 * ************************************************************************** */ 57 58 /* Expand to the token concatentation of the given macro parameters, unexpanded. 59 These are not intended for the user. */ 60 #define JITTER_CONCATENATE_TWO_UNEXPANDED(a, b) \ 61 a ## b 62 #define JITTER_CONCATENATE_THREE_UNEXPANDED(a, b, c) \ 63 a ## b ## c 64 #define JITTER_CONCATENATE_FOUR_UNEXPANDED(a, b, c, d) \ 65 a ## b ## c ## d 66 #define JITTER_CONCATENATE_FIVE_UNEXPANDED(a, b, c, d, e) \ 67 a ## b ## c ## d ## e 68 69 /* Expand to the token concatentation of the given macro parameters, after they 70 are expanded themselves. */ 71 #define JITTER_CONCATENATE_TWO(a, b) \ 72 JITTER_CONCATENATE_TWO_UNEXPANDED(a, b) 73 #define JITTER_CONCATENATE_THREE(a, b, c) \ 74 JITTER_CONCATENATE_THREE_UNEXPANDED(a, b, c) 75 #define JITTER_CONCATENATE_FOUR(a, b, c, d) \ 76 JITTER_CONCATENATE_FOUR_UNEXPANDED(a, b, c, d) 77 #define JITTER_CONCATENATE_FIVE(a, b, c, d, e) \ 78 JITTER_CONCATENATE_FIVE_UNEXPANDED(a, b, c, d, e) 79 80 81 82 83 /* Local identifier poisoning. 84 * ************************************************************************** */ 85 86 /* This feature serves to provide helpful error messages in case a code block 87 contains a use of a locally forbidden identifier. The identifier is poisoned 88 at the beginning of the block and unpoisoned at the end. 89 It is possible to poison functions, non-function globals, macros, and even C 90 keywords. 91 92 The implementation relies on non-standard GNU C features. It is used 93 conditionally in generated code. Where the feature is not supported the 94 system will fail in a less friendly way in case of incorrect code, but 95 correctness will not be compromised. */ 96 97 /* This is how to poison an indentifier foo, for example with the error message 98 about relocatable VM instructions:: 99 # pragma push_macro ("foo") 100 # undef foo 101 # define foo JITTER_FORBIDDEN_EXPRESSION_IN_RELOCATABLE (foo) 102 103 And this is how to unpoison it: 104 # pragma pop_macro ("foo") 105 106 In order to avoid spurious warning messages at the beginning of a sequence 107 of poisonings, this should be generated (once): 108 # pragma GCC diagnostic push 109 # pragma GCC diagnostic ignored "-Wpragmas" 110 # pragma GCC diagnostic ignored "-Wunknown-warning-option" 111 # pragma GCC diagnostic ignored "-Wbuiltin-macro-redefined" 112 # pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch" 113 At the end, after unpoisoning, this restores the previous diagnostics state: 114 # pragma GCC diagnostic pop */ 115 116 /* The canonic use of _Pragma with a stringized argument. */ 117 #define JITTER_PRAGMA(x) \ 118 _Pragma (#x) 119 120 /* Expand to a sequence of two _Pragma uses, the first one printing a nice error 121 message involving the given identifier and the given message (provided by the 122 caller as a string), the second one causing the compiler to fail. */ 123 #define JITTER_PRAGMA_WARN_WITH_REASON(identifier, reason_string_literal) \ 124 /* This is printed in a nicer way than #pragma GCC error. */ \ 125 JITTER_PRAGMA (message ("\nYou cannot use \"" # identifier "\" in " \ 126 JITTER_SPECIALIZED_INSTRUCTION_NAME_AS_STRING ":\n" \ 127 reason_string_literal \ 128 ".\nAny type error you may see after this " \ 129 "message is probably an effect of this macro " \ 130 "which serves to prevent the use of " \ 131 "\"" #identifier "\"." \ 132 )); \ 133 /* And now fail, as well. This literal string is printed nicely. */ \ 134 JITTER_PRAGMA (GCC error "Refusing to compile."); 135 136 /* Expand to a use of JITTER_PRAGMA_WARN_WITH_REASON with the appropriate error 137 message. */ 138 #define JITTER_POISONED_IN_ANY_INSTRUCTION(identifier) \ 139 JITTER_PRAGMA_WARN_WITH_REASON \ 140 (identifier, "it is forbidden in any VM instruction") 141 #define JITTER_POISONED_IN_RELOCATABLE_INSTRUCTION(identifier) \ 142 JITTER_PRAGMA_WARN_WITH_REASON \ 143 (identifier, \ 144 "it is forbidden in relocatable VM instructions (but you may " \ 145 "change the instruction to be non-relocatable)") 146 #define JITTER_POISONED_IN_NON_BRANCHING_INSTRUCTION(identifier) \ 147 JITTER_PRAGMA_WARN_WITH_REASON \ 148 (identifier, \ 149 "it is forbidden in non-branching VM instructions (but you may " \ 150 "change the instruction to be branching)") 151 152 /* Expand to a GNU C statement-expresison evaluating to zero (which is 153 compatible with most types in C) and a use of JITTER_PRAGMA_WARN_WITH_REASON. 154 The fact that the identifier expands to an expression makes it likely that 155 the resulting expression remains well-formed syntactically, which avoids 156 distracting syntax errors in many cases. 157 The intended error message related to the use of the identifier is printend 158 in any case. */ 159 #define JITTER_FORBIDDEN_EXPRESSION(identifier) \ 160 ({ JITTER_POISONED_IN_ANY_INSTRUCTION (identifier); 0; }) 161 #define JITTER_FORBIDDEN_EXPRESSION_IN_RELOCATABLE(identifier) \ 162 ({ JITTER_POISONED_IN_RELOCATABLE_INSTRUCTION (identifier); 0; }) 163 #define JITTER_FORBIDDEN_EXPRESSION_IN_NON_BRANCHING(identifier) \ 164 ({ JITTER_POISONED_IN_NON_BRANCHING_INSTRUCTION (identifier); 0; }) 165 166 #endif // #ifndef JITTER_CPP_H_ 167