| // RUN: %clang_cc1 -fsyntax-only -verify=expected,immediate %s |
| // RUN: %clang_cc1 -fsyntax-only -fexperimental-late-parse-attributes %s -verify=expected,late |
| |
| #define __counted_by(f) __attribute__((counted_by(f))) |
| |
| struct bar; |
| |
| struct not_found { |
| int count; |
| struct bar *fam[] __counted_by(bork); // expected-error {{use of undeclared identifier 'bork'}} |
| }; |
| |
| struct no_found_count_not_in_substruct { |
| unsigned long flags; |
| unsigned char count; // expected-note {{'count' declared here}} |
| struct A { |
| int dummy; |
| int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the annotated flexible array}} |
| } a; |
| }; |
| |
| struct not_found_count_not_in_unnamed_substruct { |
| unsigned char count; // expected-note {{'count' declared here}} |
| struct { |
| int dummy; |
| int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the annotated flexible array}} |
| } a; |
| }; |
| |
| struct not_found_count_not_in_unnamed_substruct_2 { |
| struct { |
| unsigned char count; // expected-note {{'count' declared here}} |
| }; |
| struct { |
| int dummy; |
| int array[] __counted_by(count); // expected-error {{'counted_by' field 'count' isn't within the same struct as the annotated flexible array}} |
| } a; |
| }; |
| |
| struct not_found_count_in_other_unnamed_substruct { |
| struct { |
| unsigned char count; |
| } a1; |
| |
| struct { |
| int dummy; |
| int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}} |
| }; |
| }; |
| |
| struct not_found_count_in_other_substruct { |
| struct _a1 { |
| unsigned char count; |
| } a1; |
| |
| struct { |
| int dummy; |
| int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}} |
| }; |
| }; |
| |
| struct not_found_count_in_other_substruct_2 { |
| struct _a2 { |
| unsigned char count; |
| } a2; |
| |
| int array[] __counted_by(count); // expected-error {{use of undeclared identifier 'count'}} |
| }; |
| |
| struct not_found_suggest { |
| int bork; |
| struct bar *fam[] __counted_by(blork); // expected-error {{use of undeclared identifier 'blork'}} |
| }; |
| |
| int global; // expected-note {{'global' declared here}} |
| |
| struct found_outside_of_struct { |
| int bork; |
| struct bar *fam[] __counted_by(global); // expected-error {{field 'global' in 'counted_by' not inside structure}} |
| }; |
| |
| struct self_referrential { |
| int bork; |
| // immediate-error@+2{{use of undeclared identifier 'self'}} |
| // late-error@+1{{'counted_by' requires a non-boolean integer type argument}} |
| struct bar *self[] __counted_by(self); |
| }; |
| |
| struct non_int_count { |
| double dbl_count; |
| struct bar *fam[] __counted_by(dbl_count); // expected-error {{'counted_by' requires a non-boolean integer type argument}} |
| }; |
| |
| struct array_of_ints_count { |
| int integers[2]; |
| struct bar *fam[] __counted_by(integers); // expected-error {{'counted_by' requires a non-boolean integer type argument}} |
| }; |
| |
| struct not_a_fam { |
| int count; |
| // expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct bar' is an incomplete type}} |
| struct bar *non_fam __counted_by(count); |
| }; |
| |
| struct not_a_c99_fam { |
| int count; |
| struct bar *non_c99_fam[0] __counted_by(count); // expected-error {{'counted_by' on arrays only applies to C99 flexible array members}} |
| }; |
| |
| struct annotated_with_anon_struct { |
| unsigned long flags; |
| struct { |
| unsigned char count; |
| int array[] __counted_by(crount); // expected-error {{use of undeclared identifier 'crount'}} |
| }; |
| }; |
| |
| //============================================================================== |
| // __counted_by on a struct VLA with element type that has unknown size |
| //============================================================================== |
| |
| struct size_unknown; // expected-note 2{{forward declaration of 'struct size_unknown'}} |
| struct on_member_arr_incomplete_ty_ty_pos { |
| int count; |
| // expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}} |
| // expected-error@+1{{array has incomplete element type 'struct size_unknown'}} |
| struct size_unknown buf[] __counted_by(count); |
| }; |
| |
| struct on_member_arr_incomplete_const_ty_ty_pos { |
| int count; |
| // expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}} |
| // expected-error@+1{{array has incomplete element type 'const struct size_unknown'}} |
| const struct size_unknown buf[] __counted_by(count); |
| }; |
| |
| struct on_member_arr_void_ty_ty_pos { |
| int count; |
| // expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}} |
| // expected-error@+1{{array has incomplete element type 'void'}} |
| void buf[] __counted_by(count); |
| }; |
| |
| typedef void(fn_ty)(int); |
| |
| struct on_member_arr_fn_ptr_ty { |
| int count; |
| // An Array of function pointers is allowed |
| fn_ty* buf[] __counted_by(count); |
| }; |
| |
| struct on_member_arr_fn_ty { |
| int count; |
| // An array of functions is not allowed. |
| // expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}} |
| // expected-error@+1{{'buf' declared as array of functions of type 'fn_ty' (aka 'void (int)')}} |
| fn_ty buf[] __counted_by(count); |
| }; |
| |
| |
| // `buffer_of_structs_with_unnannotated_vla`, |
| // `buffer_of_structs_with_annotated_vla`, and |
| // `buffer_of_const_structs_with_annotated_vla` are currently prevented because |
| // computing the size of `Arr` at runtime would require an O(N) walk of `Arr` |
| // elements to take into account the length of the VLA in each struct instance. |
| |
| struct has_unannotated_VLA { |
| int count; |
| char buffer[]; |
| }; |
| |
| struct has_annotated_VLA { |
| int count; |
| char buffer[] __counted_by(count); |
| }; |
| |
| struct buffer_of_structs_with_unnannotated_vla { |
| int count; |
| // Treating this as a warning is a temporary fix for existing attribute adopters. It **SHOULD BE AN ERROR**. |
| // expected-warning@+1{{'counted_by' should not be applied to an array with element of unknown size because 'struct has_unannotated_VLA' is a struct type with a flexible array member. This will be an error in a future compiler version}} |
| struct has_unannotated_VLA Arr[] __counted_by(count); |
| }; |
| |
| |
| struct buffer_of_structs_with_annotated_vla { |
| int count; |
| // Treating this as a warning is a temporary fix for existing attribute adopters. It **SHOULD BE AN ERROR**. |
| // expected-warning@+1{{'counted_by' should not be applied to an array with element of unknown size because 'struct has_annotated_VLA' is a struct type with a flexible array member. This will be an error in a future compiler version}} |
| struct has_annotated_VLA Arr[] __counted_by(count); |
| }; |
| |
| struct buffer_of_const_structs_with_annotated_vla { |
| int count; |
| // Treating this as a warning is a temporary fix for existing attribute adopters. It **SHOULD BE AN ERROR**. |
| // Make sure the `const` qualifier is printed when printing the element type. |
| // expected-warning@+1{{'counted_by' should not be applied to an array with element of unknown size because 'const struct has_annotated_VLA' is a struct type with a flexible array member. This will be an error in a future compiler version}} |
| const struct has_annotated_VLA Arr[] __counted_by(count); |
| }; |
| |