================ @@ -0,0 +1,472 @@ +// 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: + * 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); // both-warning {{declaration of 'struct prod' will not be visible outside of this function}} \ + both-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) { // both-warning {{declaration of 'struct prod' will not be visible outside of this function}} \ + both-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'}} + +// Different attributes on the tag type are an error. +struct [[gnu::packed]] attr_test { // c17-note {{previous definition is here}} \ + c23-note {{attribute 'packed' here}} + int x; +}; + +struct attr_test { // c17-error {{redefinition of 'attr_test'}} \ + c23-error {{type 'struct attr_test' has incompatible definitions}} \ + c23-note {{no corresponding attribute here}} + int x; +}; + +struct attr_test_2 { // c17-note {{previous definition is here}} \ + c23-note {{no corresponding attribute here}} + int x; +}; + +struct [[gnu::packed]] attr_test_2 { // c17-error {{redefinition of 'attr_test_2'}} \ + c23-error {{type 'struct attr_test_2' has incompatible definitions}} \ + c23-note {{attribute 'packed' here}} + int x; +}; + +struct [[deprecated]] attr_test_3 { // c17-note {{previous definition is here}} \ + c23-note {{attribute 'deprecated' here}} + int x; +}; + +struct [[gnu::packed]] attr_test_3 { // c17-error {{redefinition of 'attr_test_3'}} \ + c23-error {{type 'struct attr_test_3' has incompatible definitions}} \ + c23-note {{attribute 'packed' here}} + int x; +}; + +// Same attribute works fine! +struct [[deprecated]] attr_test_4 { // c17-note {{previous definition is here}} + int x; +}; + +struct [[deprecated]] attr_test_4 { // c17-error {{redefinition of 'attr_test_4'}} + int x; +}; + +// Same attribute with the same arguments is also fine. +struct [[deprecated("testing")]] attr_test_5 { // c17-note {{previous definition is here}} + int x; +}; + +struct [[deprecated("testing")]] attr_test_5 { // c17-error {{redefinition of 'attr_test_5'}} + int x; +}; + +// Same attribute with different arguments is not allowed. FIXME: it would be +// nicer to explain that the arguments are different, but attribute argument +// handling is already challenging. +struct [[deprecated("testing")]] attr_test_6 { // c17-note {{previous definition is here}} \ + c23-note {{attribute 'deprecated' here}} + int x; +}; + +struct [[deprecated("oh no!")]] attr_test_6 { // c17-error {{redefinition of 'attr_test_6'}} \ + c23-error {{type 'struct attr_test_6' has incompatible definitions}} \ + c23-note {{attribute 'deprecated' here}} + int x; +}; + +// Different attributes on the fields make them incompatible. +struct field_attr_test_1 { // c17-note {{previous definition is here}} + int x; + [[gnu::packed]] int y; // c23-note {{attribute 'packed' here}} +}; + +struct field_attr_test_1 { // c17-error {{redefinition of 'field_attr_test_1'}} \ + c23-error {{type 'struct field_attr_test_1' has incompatible definitions}} + int x; + int y; // c23-note {{no corresponding attribute here}} +}; + +struct field_attr_test_2 { // c17-note {{previous definition is here}} + [[gnu::packed]] int x; // c23-note {{attribute '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 incompatible definitions}} + int x; // c23-note {{no corresponding attribute here}} + int y; +}; + +struct field_attr_test_3 { // c17-note {{previous definition is here}} + [[gnu::packed]] int x; + int y; +}; + +struct field_attr_test_3 { // c17-error {{redefinition of 'field_attr_test_3'}} + int x [[gnu::packed]]; + int y; +}; + +struct field_attr_test_4 { // c17-note {{previous definition is here}} + [[gnu::packed]] int x; // c23-note {{attribute 'packed' here}} + int y; +}; + +struct field_attr_test_4 { // c17-error {{redefinition of 'field_attr_test_4'}} \ + c23-error {{type 'struct field_attr_test_4' has incompatible definitions}} + [[deprecated]] int x; // c23-note {{attribute 'deprecated' here}} + int y; +}; + +struct field_attr_test_5 { // c17-note {{previous definition is here}} + [[deprecated("testing")]] int x; + int y; +}; + +struct field_attr_test_5 { // c17-error {{redefinition of 'field_attr_test_5'}} + [[deprecated("testing")]] int x; + int y; +}; + +// Show that attribute order does not matter. +struct [[deprecated("testing"), gnu::packed]] field_attr_test_6 { // c17-note {{previous definition is here}} + int x; + int y; +}; + +struct [[gnu::packed, deprecated("testing")]] field_attr_test_6 { // c17-error {{redefinition of 'field_attr_test_6'}} + int x; + int y; +}; + +// Show that attribute syntax does matter. +// FIXME: more clearly identify the syntax as the problem. +struct [[gnu::packed]] field_attr_test_7 { // c17-note {{previous definition is here}} \ + c23-note {{attribute 'packed' here}} + int x; + int y; +}; + +struct __attribute__((packed)) field_attr_test_7 { // c17-error {{redefinition of 'field_attr_test_7'}} \ + c23-error {{type 'struct field_attr_test_7' has incompatible definitions}} \ + c23-note {{attribute 'packed' here}} + int x; + int y; +}; + +// Show that attribute *spelling* matters. These two attributes share the same +// implementation in the AST, but the spelling still matters. +struct [[nodiscard]] field_attr_test_8 { // c17-note {{previous definition is here}} \ + c23-note {{attribute 'nodiscard' here}} + int x; + int y; +}; + +struct [[gnu::warn_unused_result]] field_attr_test_8 { // c17-error {{redefinition of 'field_attr_test_8'}} \ + c23-error {{type 'struct field_attr_test_8' has incompatible definitions}} \ + c23-note {{attribute 'warn_unused_result' here}} + int x; + 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}} ---------------- AaronBallman wrote:
Good catch! Those are supposed to be equivalent, but they're not treated as such by the structural equivalence test. I'll fix that and add the test. https://github.com/llvm/llvm-project/pull/132939 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits