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