1 1.18 rillig /* $NetBSD: c23.c,v 1.18 2025/09/18 18:22:18 rillig Exp $ */ 2 1.1 rillig # 3 "c23.c" 3 1.1 rillig 4 1.1 rillig // Tests for the option -Ac23, which allows features from C23 and all earlier 5 1.1 rillig // ISO standards, but none of the GNU extensions. 6 1.1 rillig // 7 1.1 rillig // See also: 8 1.7 rillig // c11.c 9 1.3 rillig // msg_353.c for empty initializer braces 10 1.1 rillig 11 1.15 rillig /* lint1-flags: -Ac23 -hw -X 351 */ 12 1.1 rillig 13 1.9 rillig 14 1.9 rillig int 15 1.9 rillig bool_is_predefined_in_c23(void) 16 1.9 rillig { 17 1.9 rillig bool t = true; 18 1.9 rillig bool f = false; 19 1.9 rillig return (t == true ? 20 : 0) + (f == false ? 3 : 0); 20 1.9 rillig } 21 1.9 rillig 22 1.9 rillig int 23 1.9 rillig c99_bool_is_still_valid_in_c23(void) 24 1.9 rillig { 25 1.9 rillig _Bool t = 1; 26 1.9 rillig _Bool f = 0; 27 1.9 rillig return (t == 1 ? 20 : 0) + (f == 0 ? 3 : 0); 28 1.9 rillig } 29 1.9 rillig 30 1.9 rillig 31 1.11 rillig bool 32 1.11 rillig null_pointer_constant(const char *p, double dbl) 33 1.11 rillig { 34 1.11 rillig /* expect+1: error: operands of '!=' have incompatible types 'double' and 'pointer to void' [107] */ 35 1.11 rillig if (dbl != nullptr) 36 1.11 rillig p++; 37 1.11 rillig if (dbl > 0.0) 38 1.11 rillig p++; 39 1.11 rillig if (*p == '\0') 40 1.11 rillig p = nullptr; 41 1.11 rillig return p == nullptr; 42 1.11 rillig } 43 1.11 rillig 44 1.11 rillig 45 1.12 rillig void * 46 1.12 rillig storage_class_in_compound_literal(void) 47 1.12 rillig { 48 1.12 rillig typedef struct node node; 49 1.12 rillig struct node { 50 1.12 rillig node *left; 51 1.12 rillig int value; 52 1.12 rillig node *right; 53 1.12 rillig }; 54 1.12 rillig 55 1.12 rillig node *tree; 56 1.12 rillig tree = &(static node){ 57 1.12 rillig &(static node){ 58 1.12 rillig nullptr, 59 1.12 rillig 3, 60 1.12 rillig nullptr, 61 1.12 rillig }, 62 1.12 rillig 5, 63 1.12 rillig nullptr, 64 1.12 rillig }; 65 1.12 rillig return tree->left; 66 1.12 rillig } 67 1.12 rillig 68 1.1 rillig int 69 1.3 rillig empty_initializer_braces(void) 70 1.1 rillig { 71 1.1 rillig struct s { 72 1.1 rillig int member; 73 1.1 rillig } s; 74 1.1 rillig 75 1.2 rillig // Empty initializer braces were introduced in C23. 76 1.1 rillig s = (struct s){}; 77 1.1 rillig s = (struct s){s.member}; 78 1.1 rillig return s.member; 79 1.1 rillig } 80 1.2 rillig 81 1.7 rillig 82 1.7 rillig _Static_assert(1 > 0, "string"); 83 1.7 rillig _Static_assert(1 > 0); 84 1.7 rillig 85 1.7 rillig 86 1.2 rillig // The keyword 'thread_local' was introduced in C23. 87 1.2 rillig thread_local int globally_visible; 88 1.2 rillig 89 1.3 rillig // Thread-local functions don't make sense; lint allows them, though. 90 1.2 rillig thread_local void 91 1.2 rillig thread_local_function(void) 92 1.2 rillig { 93 1.2 rillig } 94 1.2 rillig 95 1.2 rillig void 96 1.2 rillig function(void) 97 1.2 rillig { 98 1.2 rillig // Not sure whether it makes sense to have a function-scoped 99 1.2 rillig // thread-local variable. Don't warn for now, let the compilers handle 100 1.2 rillig // this case. 101 1.2 rillig thread_local int function_scoped_thread_local; 102 1.2 rillig } 103 1.4 rillig 104 1.6 rillig // 'thread_local' can be combined with 'extern' and 'static', but with no other 105 1.6 rillig // storage classes. The other storage classes cannot be combined. 106 1.4 rillig extern thread_local int extern_thread_local_1; 107 1.4 rillig thread_local extern int extern_thread_local_2; 108 1.8 rillig /* expect+1: warning: static variable 'static_thread_local_1' unused [226] */ 109 1.6 rillig static thread_local int static_thread_local_1; 110 1.8 rillig /* expect+1: warning: static variable 'static_thread_local_2' unused [226] */ 111 1.6 rillig thread_local static int static_thread_local_2; 112 1.13 rillig 113 1.13 rillig 114 1.13 rillig int 115 1.13 rillig attributes(int i) 116 1.13 rillig { 117 1.13 rillig // An attribute specifier list may be empty. 118 1.13 rillig [[]]i++; 119 1.13 rillig 120 1.13 rillig // There may be leading or trailing commas. 121 1.13 rillig [[,]]i++; 122 1.13 rillig 123 1.13 rillig // There may be arbitrary commas around or between the attributes. 124 1.13 rillig [[,,,,,]]i++; 125 1.13 rillig 126 1.13 rillig // An attribute may be a plain identifier without arguments. 127 1.13 rillig [[identifier]]i++; 128 1.13 rillig 129 1.13 rillig // The identifier may be prefixed with one additional identifier. 130 1.13 rillig [[prefix::identifier]]i++; 131 1.13 rillig 132 1.13 rillig // An attribute may have empty arguments. 133 1.13 rillig [[identifier()]]i++; 134 1.13 rillig 135 1.13 rillig // The arguments of an attribute may be arbitrary tokens. 136 1.13 rillig [[identifier([])]]i++; 137 1.13 rillig 138 1.13 rillig // The commas in this "argument list" are ordinary punctuator tokens, 139 1.13 rillig // they do not separate any arguments. 140 1.13 rillig // The structure of the attribute argument is: 141 1.13 rillig // 1. empty balanced token sequence between '[' and ']' 142 1.13 rillig // 2. token ',' 143 1.13 rillig // 3. empty balanced token sequence between '{' and '}' 144 1.13 rillig // 4. token ',' 145 1.13 rillig // 5. empty balanced token sequence between '(' and ')' 146 1.13 rillig [[identifier([], {}, ())]]i++; 147 1.13 rillig 148 1.13 rillig // Inside an argument, parentheses may be nested. 149 1.13 rillig [[identifier(((((())))))]]i++; 150 1.13 rillig // Inside an argument, brackets may be nested. 151 1.13 rillig [[identifier([[[[[]]]]])]]i++; 152 1.13 rillig // Inside an argument, braces may be nested. 153 1.13 rillig [[identifier({{{{{}}}}})]]i++; 154 1.13 rillig 155 1.13 rillig // An attribute argument may contain arbitrary punctuation. 156 1.13 rillig [[identifier(++++ ? ? ? : : :: )]]i++; 157 1.13 rillig 158 1.13 rillig // An attribute argument may contain constants and string literals. 159 1.13 rillig [[identifier(0, 0.0, "hello" " " "world")]]i++; 160 1.13 rillig 161 1.13 rillig // There may be multiple attribute specifier sequences in a row. 162 1.13 rillig [[]][[]][[]]i++; 163 1.13 rillig 164 1.17 rillig // An attribute may occur more than once. 165 1.17 rillig [[ 166 1.17 rillig maybe_unused, maybe_unused, maybe_unused, maybe_unused, 167 1.17 rillig maybe_unused, maybe_unused, maybe_unused, maybe_unused, 168 1.17 rillig maybe_unused, maybe_unused, maybe_unused, maybe_unused, 169 1.17 rillig maybe_unused, maybe_unused, maybe_unused, maybe_unused, 170 1.17 rillig maybe_unused, maybe_unused, maybe_unused, maybe_unused, 171 1.17 rillig ]]i++; 172 1.17 rillig 173 1.13 rillig return i; 174 1.13 rillig } 175 1.14 rillig 176 1.14 rillig typedef int number; 177 1.14 rillig 178 1.14 rillig void 179 1.14 rillig attributes_in_parameter_declaration( 180 1.14 rillig [[maybe_unused]] int int_param, 181 1.14 rillig [[maybe_unused]] const int const_int_param, 182 1.14 rillig [[maybe_unused]] number typedef_param, 183 1.14 rillig [[maybe_unused]] const number const_typedef_param) 184 1.14 rillig { 185 1.14 rillig } 186 1.15 rillig 187 1.15 rillig int 188 1.15 rillig attribute_in_switch_statement(int n) 189 1.15 rillig { 190 1.15 rillig switch (n) { 191 1.15 rillig case 1: 192 1.15 rillig n++; 193 1.15 rillig /* expect+1: warning: fallthrough on case statement [220] */ 194 1.15 rillig case 2: 195 1.15 rillig n++; 196 1.15 rillig [[fallthrough]]; 197 1.15 rillig case 3: 198 1.15 rillig n++; 199 1.15 rillig [[fallthrough]]; 200 1.15 rillig default: 201 1.15 rillig n++; 202 1.15 rillig } 203 1.15 rillig return n; 204 1.15 rillig } 205 1.18 rillig 206 1.18 rillig // C23 6.7.7.4p13 says that "()" is equivalent to "(void)". 207 1.18 rillig void function_without_parameters(); 208