1/*	$NetBSD: c23.c,v 1.13 2024/05/11 16:12:28 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 -w -X 351 */
12
13
14int
15bool_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
22int
23c99_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
31bool
32null_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
45void *
46storage_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
68int
69empty_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.
87thread_local int globally_visible;
88
89// Thread-local functions don't make sense; lint allows them, though.
90thread_local void
91thread_local_function(void)
92{
93}
94
95void
96function(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.
106extern thread_local int extern_thread_local_1;
107thread_local extern int extern_thread_local_2;
108/* expect+1: warning: static variable 'static_thread_local_1' unused [226] */
109static thread_local int static_thread_local_1;
110/* expect+1: warning: static variable 'static_thread_local_2' unused [226] */
111thread_local static int static_thread_local_2;
112
113
114int
115attributes(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	return i;
165}
166