1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
|
// RUN: %clang_cc1 -fsyntax-only -std=c23 -pedantic -Wall -Wno-comment -verify=both,c23 %s
// RUN: %clang_cc1 -fsyntax-only -std=c17 -pedantic -Wall -Wno-comment -Wno-c23-extensions -verify=both,c17 %s
/* WG14 N3037: Clang 21
* Improved tag compatibility
*
* Identical tag types have always been compatible across TU boundaries. This
* paper made identical tag types compatible within the same TU.
*/
struct foo { int a; } p;
void baz(struct foo f); // c17-note {{passing argument to parameter 'f' here}}
void bar(void) {
struct foo { int a; } q = {};
baz(q); // c17-error {{passing 'struct foo' to parameter of incompatible type 'struct foo'}}
}
#define PRODUCT(A ,B) struct prod { A a; B b; } // expected-note 2 {{expanded from macro 'PRODUCT'}}
#define SUM(A, B) struct sum { _Bool flag; union { A a; B b; }; } // expected-note 2 {{expanded from macro 'SUM'}}
void func1(PRODUCT(int, SUM(float, double)) x); // c17-warning {{declaration of 'struct prod' will not be visible outside of this function}} \
c17-warning {{declaration of 'struct sum' will not be visible outside of this function}} \
c17-note {{passing argument to parameter 'x' here}}
void func2(PRODUCT(int, SUM(float, double)) y) { // c17-warning {{declaration of 'struct prod' will not be visible outside of this function}} \
c17-warning {{declaration of 'struct sum' will not be visible outside of this function}}
func1(y); // c17-error {{passing 'struct prod' to parameter of incompatible type 'struct prod'}}
}
struct foop { struct { int x; }; }; // c17-note {{previous definition is here}}
struct foop { struct { int x; }; }; // c17-error {{redefinition of 'foop'}}
union barp { int x; float y; }; // c17-note {{previous definition is here}}
union barp { int x; float y; }; // c17-error {{redefinition of 'barp'}}
typedef struct q { int x; } q_t; // c17-note 2 {{previous definition is here}}
typedef struct q { int x; } q_t; // c17-error {{redefinition of 'q'}} \
c17-error-re {{typedef redefinition with different types ('struct (unnamed struct at {{.*}})' vs 'struct q')}}
void func3(void) {
struct S { int x; }; // c17-note {{previous definition is here}}
struct T { struct S s; }; // c17-note {{previous definition is here}}
struct S { int x; }; // c17-error {{redefinition of 'S'}}
struct T { struct S s; }; // c17-error {{redefinition of 'T'}}
}
struct food { int (*p)[3]; }; // c23-note {{field 'p' has type 'int (*)[3]' here}} \
c17-note {{previous definition is here}}
struct food { int (*p)[]; }; // c23-error {{type 'struct food' has incompatible definitions}} \
c23-note {{field 'p' has type 'int (*)[]' here}} \
c17-error {{redefinition of 'food'}}
union bard { int x; float y; }; // c23-note {{field has name 'x' here}} \
c17-note {{previous definition is here}}
union bard { int z; float y; }; // c23-error {{type 'union bard' has incompatible definitions}} \
c23-note {{field has name 'z' here}} \
c17-error {{redefinition of 'bard'}}
union purr { int x; float y; }; // c23-note {{field has name 'x' here}} \
c17-note {{previous definition is here}}
union purr { float y; int x; }; // c23-error {{type 'union purr' has incompatible definitions}} \
c23-note {{field has name 'y' here}} \
c17-error {{redefinition of 'purr'}}
// The presence of an attribute makes two types not compatible.
struct [[gnu::packed]] attr_test { // c17-note {{previous definition is here}} \
c23-note {{attribute 'gnu::packed' here}}
int x;
};
struct attr_test { // c17-error {{redefinition of 'attr_test'}} \
c23-error {{type 'struct attr_test' has an attribute which currently causes the types to be treated as though they are incompatible}}
int x;
};
struct attr_test_2 { // c17-note {{previous definition is here}}
int x;
};
struct [[gnu::packed]] attr_test_2 { // c17-error {{redefinition of 'attr_test_2'}} \
c23-error {{type 'struct attr_test_2' has an attribute which currently causes the types to be treated as though they are incompatible}} \
c23-note {{attribute 'gnu::packed' here}}
int x;
};
// This includes the same attribute on both types.
struct [[gnu::packed]] attr_test_3 { // c17-note {{previous definition is here}} \
c23-note {{attribute 'gnu::packed' here}}
int x;
};
struct [[gnu::packed]] attr_test_3 { // c17-error {{redefinition of 'attr_test_3'}} \
c23-error {{type 'struct attr_test_3' has an attribute which currently causes the types to be treated as though they are incompatible}} \
c23-note {{attribute 'gnu::packed' here}}
int x;
};
// Everything which applies to the tag itself also applies to fields.
struct field_attr_test_1 { // c17-note {{previous definition is here}}
int x;
[[gnu::packed]] int y; // c23-note {{attribute 'gnu::packed' here}}
};
struct field_attr_test_1 { // c17-error {{redefinition of 'field_attr_test_1'}} \
c23-error {{type 'struct field_attr_test_1' has a member with an attribute which currently causes the types to be treated as though they are incompatible}}
int x;
int y;
};
struct field_attr_test_2 { // c17-note {{previous definition is here}}
[[gnu::packed]] int x; // c23-note {{attribute 'gnu::packed' here}}
int y;
};
struct field_attr_test_2 { // c17-error {{redefinition of 'field_attr_test_2'}} \
c23-error {{type 'struct field_attr_test_2' has a member with an attribute which currently causes the types to be treated as though they are incompatible}}
int x;
int y;
};
struct field_attr_test_3 { // c17-note {{previous definition is here}}
[[gnu::packed]] int x; // c23-note {{attribute 'gnu::packed' here}}
int y;
};
struct field_attr_test_3 { // c17-error {{redefinition of 'field_attr_test_3'}} \
c23-error {{type 'struct field_attr_test_3' has a member with an attribute which currently causes the types to be treated as though they are incompatible}}
int x [[gnu::packed]]; // c23-note {{attribute 'gnu::packed' here}}
int y;
};
// Show that equivalent field types are not an issue.
typedef int typedef_of_type_int;
struct equivalent_field_types { // c17-note {{previous definition is here}}
int x;
};
struct equivalent_field_types { // c17-error {{redefinition of 'equivalent_field_types'}}
typedef_of_type_int x;
};
struct quals_matter { // c17-note {{previous definition is here}}
int x; // c23-note {{field 'x' has type 'int' here}}
};
struct quals_matter { // c17-error {{redefinition of 'quals_matter'}} \
c23-error {{type 'struct quals_matter' has incompatible definitions}}
const int x; // c23-note {{field 'x' has type 'const int' here}}
};
struct qual_order_does_not_matter { // c17-note {{previous definition is here}}
const volatile int x;
};
struct qual_order_does_not_matter { // c17-error {{redefinition of 'qual_order_does_not_matter'}}
volatile const int x;
};
struct nested { // both-note {{previous definition is here}}
int x;
struct nested { // both-error {{nested redefinition of 'nested'}}
int x;
};
};
// Show that bit-field order does matter, including anonymous bit-fields.
struct bit_field_1 { // c17-note 2 {{previous definition is here}}
int a : 1;
int : 0; // c23-note {{field has name '' here}}
int b : 1;
};
struct bit_field_1 { // c17-error {{redefinition of 'bit_field_1'}}
int a : 1;
int : 0;
int b : 1;
};
struct bit_field_1 { // c17-error {{redefinition of 'bit_field_1'}} \
c23-error {{type 'struct bit_field_1' has incompatible definitions}}
int a : 1;
int b : 1; // c23-note {{field has name 'b' here}}
};
struct bit_field_2 { // c17-note {{previous definition is here}}
int a : 1;
int b : 1; // c23-note {{bit-field 'b' has bit-width 1 here}}
};
struct bit_field_2 { // c17-error {{redefinition of 'bit_field_2'}} \
c23-error {{type 'struct bit_field_2' has incompatible definitions}}
int a : 1;
int b : 2; // c23-note {{bit-field 'b' has bit-width 2 here}}
};
// Test a bit-field with an attribute.
struct bit_field_3 { // c17-note {{previous definition is here}}
int a : 1;
int b : 1;
};
struct bit_field_3 { // c17-error {{redefinition of 'bit_field_3'}} \
c23-error {{type 'struct bit_field_3' has a member with an attribute which currently causes the types to be treated as though they are incompatible}}
int a : 1;
[[deprecated]] int b : 1; // c23-note {{attribute 'deprecated' here}}
};
struct bit_field_4 { // c17-note {{previous definition is here}}
int a : 1;
int b : 1; // c23-note {{bit-field 'b' has bit-width 1 here}}
};
struct bit_field_4 { // c17-error {{redefinition of 'bit_field_4'}} \
c23-error {{type 'struct bit_field_4' has incompatible definitions}}
int a : 1;
int b; // c23-note {{field 'b' is not a bit-field}}
};
struct bit_field_5 { // c17-note {{previous definition is here}}
int a : 1;
int b; // c23-note {{field 'b' is not a bit-field}}
};
struct bit_field_5 { // c17-error {{redefinition of 'bit_field_5'}} \
c23-error {{type 'struct bit_field_5' has incompatible definitions}}
int a : 1;
int b : 1; // c23-note {{bit-field 'b' has bit-width 1 here}}
};
struct bit_field_6 { // c17-note {{previous definition is here}}
int a : 2;
};
struct bit_field_6 { // c17-error {{redefinition of 'bit_field_6'}}
int a : 1 + 1;
};
enum E { A }; // c17-note 2 {{previous definition is here}}
enum E { A }; // c17-error {{redefinition of 'E'}} \
c17-error {{redefinition of enumerator 'A'}}
enum Q { D = 1 }; // c17-note 2 {{previous definition is here}}
enum Q { D = D }; // c17-error {{redefinition of 'Q'}} \
c17-error {{redefinition of enumerator 'D'}}
// The order of the enumeration constants does not matter, only the values do.
enum X { B = 1, C = 1 + 1 }; // c17-note 3 {{previous definition is here}}
enum X { C = 2, B = 1 }; // c17-error {{redefinition of 'X'}} \
c17-error {{redefinition of enumerator 'C'}} \
c17-error {{redefinition of enumerator 'B'}}
// Different enumeration constants.
enum Y { YA = 1, YB = 2 }; // c23-note {{enumerator 'YB' with value 2 here}} \
c17-note 3 {{previous definition is here}}
enum Y { YA = 1, YB = 3 }; // c23-error {{type 'enum Y' has incompatible definitions}} \
c23-note {{enumerator 'YB' with value 3 here}} \
c17-error {{redefinition of 'Y'}} \
c17-error {{redefinition of enumerator 'YA'}} \
c17-error {{redefinition of enumerator 'YB'}}
// Different enumeration names, same named constants.
enum Z1 { ZC = 1 }; // both-note {{previous definition is here}}
enum Z2 { ZC = 1 }; // both-error {{redefinition of enumerator 'ZC'}}
// Test attributes on the enumeration and enumerators.
enum [[deprecated]] enum_attr_test_1 { // c17-note {{previous definition is here}} \
c23-note {{attribute 'deprecated' here}}
EAT1 [[deprecated]] // c17-note {{previous definition is here}} \
c23-note {{attribute 'deprecated' here}}
};
enum [[deprecated]] enum_attr_test_1 { // c17-error {{redefinition of 'enum_attr_test_1'}} \
c23-error {{type 'enum enum_attr_test_1' has an attribute which currently causes the types to be treated as though they are incompatible}} \
c23-error {{type 'enum enum_attr_test_1' has a member with an attribute which currently causes the types to be treated as though they are incompatible}} \
c23-note {{attribute 'deprecated' here}}
EAT1 [[deprecated]] // c17-error {{redefinition of enumerator 'EAT1'}} \
c23-note {{attribute 'deprecated' here}}
};
enum [[deprecated]] enum_attr_test_2 { // c17-note {{previous definition is here}} \
c23-note {{attribute 'deprecated' here}}
EAT2 // c17-note {{previous definition is here}}
};
enum enum_attr_test_2 { // c17-error {{redefinition of 'enum_attr_test_2'}} \
c23-error {{type 'enum enum_attr_test_2' has an attribute which currently causes the types to be treated as though they are incompatible}}
EAT2 // c17-error {{redefinition of enumerator 'EAT2'}}
};
enum enum_attr_test_3 { // c17-note {{previous definition is here}}
EAT3 // c17-note {{previous definition is here}}
};
enum [[deprecated]] enum_attr_test_3 { // c17-error {{redefinition of 'enum_attr_test_3'}} \
c23-error {{type 'enum enum_attr_test_3' has an attribute which currently causes the types to be treated as though they are incompatible}} \
c23-note {{attribute 'deprecated' here}}
EAT3 // c17-error {{redefinition of enumerator 'EAT3'}}
};
// You cannot declare one with a fixed underlying type and the other without a
// fixed underlying type, or a different underlying type. However, it's worth
// showing that the underlying type doesn't change the redefinition behavior.
enum fixed_test_1 : int { FT1 }; // c17-note 2 {{previous definition is here}}
enum fixed_test_1 : int { FT1 }; // c17-error {{redefinition of 'fixed_test_1'}} \
c17-error {{redefinition of enumerator 'FT1'}}
enum fixed_test_2 : int { FT2 }; // c17-note 2 {{previous definition is here}}
enum fixed_test_2 : typedef_of_type_int { FT2 }; // c17-error {{redefinition of 'fixed_test_2'}} \
c17-error {{redefinition of enumerator 'FT2'}}
// Test more bizarre situations in terms of where the type is declared. This
// has always been allowed.
struct declared_funny_1 { int x; }
declared_funny_func(struct declared_funny_1 { int x; } arg) { // c17-warning {{declaration of 'struct declared_funny_1' will not be visible outside of this function}}
return declared_funny_func((__typeof__(arg)){ 0 });
}
// However, this is new.
struct Outer {
struct Inner { // c17-note {{previous definition is here}}
int x;
} i;
enum InnerEnum { // c17-note {{previous definition is here}}
IE1 // c17-note {{previous definition is here}}
} j;
};
struct Inner { // c17-error {{redefinition of 'Inner'}}
int x;
};
enum InnerEnum { // c17-error {{redefinition of 'InnerEnum'}}
IE1 // c17-error {{redefinition of enumerator 'IE1'}}
};
void hidden(void) {
struct hidden_struct { int x; };
}
struct hidden_struct { // This is fine because the previous declaration is not visible.
int y;
int z;
};
struct array { int y; int x[]; }; // c17-note {{previous definition is here}} \
c23-note {{field 'x' has type 'int[]' here}}
struct array { int y; int x[0]; }; // c17-error {{redefinition of 'array'}} \
c23-error {{type 'struct array' has incompatible definitions}} \
c23-note {{field 'x' has type 'int[0]' here}} \
both-warning {{zero size arrays are an extension}}
// So long as the bounds are the same value, everything is fine. They do not
// have to be token equivalent.
struct array_2 { int y; int x[3]; }; // c17-note {{previous definition is here}}
struct array_2 { int y; int x[1 + 1 + 1]; }; // c17-error {{redefinition of 'array_2'}}
struct alignment { // c17-note {{previous definition is here}}
_Alignas(int) int x; // c23-note {{attribute '_Alignas' here}}
};
struct alignment { // c17-error {{redefinition of 'alignment'}} \
c23-error {{type 'struct alignment' has a member with an attribute which currently causes the types to be treated as though they are incompatible}}
int x;
};
// Both structures need to have a tag in order to be compatible within the same
// translation unit.
struct {int i;} nontag;
struct tag {int i;} tagged; // c17-note 2 {{previous definition is here}}
_Static_assert(1 == _Generic(tagged, struct tag {int i;}:1, default:0)); // c17-error {{redefinition of 'tag'}} \
c17-error {{static assertion failed}}
_Static_assert(0 == _Generic(tagged, struct {int i;}:1, default:0));
_Static_assert(0 == _Generic(nontag, struct tag {int i;}:1, default:0)); // c17-error {{redefinition of 'tag'}}
// That means these two structures are not actually compatible; see GH141724.
_Static_assert(0 == _Generic(nontag, struct {int i;}:1, default:0));
// Also test the behavior within a function (so the declaration context is not
// at the translation unit level).
void nontag_func_test(void) {
struct { int i; } test;
_Static_assert(0 == _Generic(test, struct { int i; } : 1, default : 0));
}
// Same kind of test, but this time for a declaration in the parameter list.
void nontag_param_test(struct { int i; } herp) {
_Static_assert(0 == _Generic(herp, struct { int i; } : 1, default : 0));
}
// Same kind of test, but demonstrating that these still aren't compatible.
void nontag_both_in_params(struct { int i; } Arg1, struct { int i; } Arg2) {
_Static_assert(0 == _Generic(__typeof__(Arg1), __typeof__(Arg2) : 1, default : 0)); // both-warning {{passing a type argument as the first operand to '_Generic' is a C2y extension}}
}
struct InnerAnonStruct {
struct {
int i;
} untagged;
} inner_anon_tagged;
_Static_assert(0 == _Generic(inner_anon_tagged.untagged, struct { int i; } : 1, default : 0));
// Test the same thing with enumerations (test for unions is omitted because
// unions and structures are both RecordDecl objects, whereas EnumDecl is not).
enum { E_Untagged1 } nontag_enum; // both-note {{previous definition is here}}
_Static_assert(0 == _Generic(nontag_enum, enum { E_Untagged1 } : 1, default : 0)); // both-error {{redefinition of enumerator 'E_Untagged1'}}
// Test that enumerations with mixed underlying types are properly handled.
enum GH150594_E1 : int { GH150594_Val1 };
enum GH150594_E2 : int { GH150594_Val2 };
enum GH150594_E3 { GH150594_Val3 };
enum GH150594_E4 : int { GH150594_Val4 };
void GH150594(void) {
extern enum GH150594_E1 Fn1(void); // both-note {{previous declaration is here}}
extern enum GH150594_E2 Fn2(void); // c17-note {{previous declaration is here}}
extern enum GH150594_E3 Fn3(void); // both-note {{previous declaration is here}}
extern enum GH150594_E4 Fn4(void); // both-note {{previous declaration is here}}
enum GH150594_E1 { GH150594_Val1 };
enum GH150594_E2 : int { GH150594_Val2 };
enum GH150594_E3 : int { GH150594_Val3 };
enum GH150594_E4 : short { GH150594_Val4 };
extern enum GH150594_E1 Fn1(void); // both-error {{conflicting types for 'Fn1'}}
extern enum GH150594_E2 Fn2(void); // c17-error {{conflicting types for 'Fn2'}}
extern enum GH150594_E3 Fn3(void); // both-error {{conflicting types for 'Fn3'}}
extern enum GH150594_E4 Fn4(void); // both-error {{conflicting types for 'Fn4'}}
// Show that two declarations in the same scope give expected diagnostics.
enum E1 { e1 }; // both-note {{previous declaration is here}}
enum E1 : int { e1 }; // both-error {{enumeration previously declared with nonfixed underlying type}}
enum E2 : int { e2 }; // both-note {{previous declaration is here}}
enum E2 { e2 }; // both-error {{enumeration previously declared with fixed underlying type}}
enum E3 : int { e3 }; // both-note {{previous declaration is here}}
enum E3 : short { e3 }; // both-error {{enumeration redeclared with different underlying type 'short' (was 'int')}}
typedef short foo;
enum E4 : foo { e4 }; // c17-note 2 {{previous definition is here}}
enum E4 : short { e4 }; // c17-error {{redefinition of 'E4'}} \
c17-error {{redefinition of enumerator 'e4'}}
enum E5 : foo { e5 }; // both-note {{previous declaration is here}}
enum E5 : int { e5 }; // both-error {{enumeration redeclared with different underlying type 'int' (was 'foo' (aka 'short'))}}
}
// Test that enumerations are compatible with their underlying type, but still
// diagnose when "same type" is required rather than merely "compatible type".
enum E1 : int { e1 }; // Fixed underlying type
enum E2 { e2 }; // Unfixed underlying type, defaults to int or unsigned int
struct GH149965_1 { int h; };
// This typeof trick is used to get the underlying type of the enumeration in a
// platform agnostic way.
struct GH149965_2 { __typeof__(+(enum E2){}) h; };
void gh149965(void) {
extern struct GH149965_1 x1; // c17-note {{previous declaration is here}}
extern struct GH149965_2 x2; // c17-note {{previous declaration is here}}
// Both the structure and the variable declarations are fine because only a
// compatible type is required, not the same type, because the structures are
// declared in different scopes.
struct GH149965_1 { enum E1 h; };
struct GH149965_2 { enum E2 h; };
extern struct GH149965_1 x1; // c17-error {{redeclaration of 'x1'}}
extern struct GH149965_2 x2; // c17-error {{redeclaration of 'x2'}}
// However, in the same scope, the same type is required, not just compatible
// types.
// FIXME: this should be an error in both C17 and C23 mode.
struct GH149965_3 { int h; }; // c17-note {{previous definition is here}}
struct GH149965_3 { enum E1 h; }; // c17-error {{redefinition of 'GH149965_3'}}
// For Clang, the composite type after declaration merging is the enumeration
// type rather than an integer type.
enum E1 *eptr;
[[maybe_unused]] __typeof__(x1.h) *ptr = eptr;
enum E2 *eptr2;
[[maybe_unused]] __typeof__(x2.h) *ptr2 = eptr2;
}
|