================ @@ -0,0 +1,584 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify %s + +#define __counted_by(f) __attribute__((counted_by(f))) + +// ============================================================================= +// # Struct incomplete type with attribute in the decl position +// ============================================================================= + +// Note: This could be considered misleading. The typedef isn't actually on this +// line. Also note the discrepancy in diagnostic count (27 vs 51) is due to +// the pointer arithmetic on incomplete pointee type diagnostic always using +// diagnostic text that refers to the underlying forward decl, even when the +// typedef is used. +// expected-note@+1 27{{forward declaration of 'Incomplete_t' (aka 'struct IncompleteTy')}} +struct IncompleteTy; // expected-note 51{{forward declaration of 'struct IncompleteTy'}} + +typedef struct IncompleteTy Incomplete_t; + +struct CBBufDeclPos { + int count; + struct IncompleteTy* buf __counted_by(count); // OK expected-note 27{{__counted_by attribute is here}} + Incomplete_t* buf_typedef __counted_by(count); // OK expected-note 27{{__counted_by attribute is here}} +}; + +void consume_struct_IncompleteTy(struct IncompleteTy* buf); + +int idx(void); + + + +void test_CBBufDeclPos(struct CBBufDeclPos* ptr) { + // =========================================================================== + // ## Local variable initialization + // =========================================================================== + struct CBBufDeclPos explicit_desig_init = { + .count = 0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + .buf = 0x0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + .buf_typedef = 0x0 + }; + // Variable is not currently marked as invalid so uses of the variable allows + // diagnostics to fire. + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + explicit_desig_init.buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + explicit_desig_init.buf_typedef = 0x0; + // expected-error@+1{{cannot use 'explicit_desig_init.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + void *tmp = explicit_desig_init.buf; + // expected-error@+1{{cannot use 'explicit_desig_init.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + void *tmp2 = explicit_desig_init.buf_typedef; + + struct CBBufDeclPos partial_explicit_desig_init = { + .count = 0, + // .buf and .buf_typedef are implicit zero initialized + // expected-error@+2{{cannot implicitly initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + }; + + struct CBBufDeclPos implicit_full_init = { + 0 + // expected-error@+2{{cannot implicitly initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + }; + // Variable is not currently marked as invalid so uses of the variable allows + // diagnostics to fire. + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + implicit_full_init.buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + implicit_full_init.buf_typedef = 0x0; + // expected-error@+1{{cannot use 'implicit_full_init.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + void* tmp3 = implicit_full_init.buf; + // expected-error@+1{{cannot use 'implicit_full_init.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + void* tmp4 = implicit_full_init.buf_typedef; + + struct CBBufDeclPos explicit_non_desig_init = { + 0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + 0x0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + 0x0 + }; + + // =========================================================================== + // ## Assignment to fields + // =========================================================================== + struct CBBufDeclPos uninit; + uninit.count = 0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + uninit.buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + uninit.buf_typedef = 0x0; + ptr->count = 0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + ptr->buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + ptr->buf_typedef = 0x0; + + + // =========================================================================== + // ## Make sure modifying the fields through other assignment operators is not + // allowed + // =========================================================================== + uninit.buf++; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + ++uninit.buf; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + uninit.buf += 1; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + uninit.buf_typedef++; // // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + ++uninit.buf_typedef; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + uninit.buf_typedef -= 1; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + + uninit.buf--; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + --uninit.buf; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + uninit.buf -= 1; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + uninit.buf_typedef--; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + --uninit.buf_typedef; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + uninit.buf_typedef -= 1; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + + ptr->buf++; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + ++ptr->buf; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + ptr->buf += 1; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + ptr->buf--; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + --ptr->buf; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + ptr->buf -= 1; // expected-error{{arithmetic on a pointer to an incomplete type 'struct IncompleteTy'}} + + ptr->buf_typedef++; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + ++ptr->buf_typedef; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + ptr->buf_typedef += 1; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + ptr->buf_typedef--; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + --ptr->buf_typedef; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + ptr->buf_typedef -= 1; // expected-error{{arithmetic on a pointer to an incomplete type 'Incomplete_t' (aka 'struct IncompleteTy')}} + + // =========================================================================== + // ## Use of fields in expressions + // =========================================================================== + // expected-error@+2{{cannot use 'uninit.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + void* addr = + ((char*) uninit.buf ) + 1; + // expected-error@+2{{cannot use 'uninit.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + void* addr_typedef = + ((char*) uninit.buf_typedef ) + 1; + // expected-error@+2{{cannot use 'ptr->buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + void* addr_ptr = + ((char*) ptr->buf ) + 1; + // expected-error@+2{{cannot use 'ptr->buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + void* addr_ptr_typedef = + ((char*) ptr->buf_typedef ) + 1; + + // =========================================================================== + // ## Take address of fields + // =========================================================================== + // TODO: This should be forbidden, not because of the incomplete pointee type + // but because in the -fbounds-safety language model the address of a + // `counted_by` pointer cannot be taken to avoid it being possible to modify + // the `counted_by` pointer through another pointer. Whether or not this + // should be forbidden when `-fbounds-safety` is off is TBD. + // + // The incomplete pointee type isn't actually a problem here for + // `-fbounds-safety` because taking the address of a pointer returns a pointer + // that have the bounds of a single `void*`, so bounds checks on the resulting + // pointer don't need to know `sizeof(struct IncompleteTy)` but instead + // `sizeof(struct IncompleteTy* buf __counted_by(count))` which is just the + // size of a pointer. + void* take_addr = &uninit.buf; + void* take_addr_typedef = &uninit.buf_typedef; + void* take_addr_ptr = &ptr->buf; + void* take_addr_ptr_typedef = &ptr->buf_typedef; + + // expected-error@+1{{cannot use 'uninit.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_zero = &uninit.buf[0]; + // expected-error@+1{{cannot use 'uninit.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_idx = &uninit.buf[idx()]; + + // expected-error@+1{{cannot use 'uninit.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_zero_typedef = &uninit.buf_typedef[0]; + // expected-error@+1{{cannot use 'uninit.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_idx_typedef = &uninit.buf_typedef[idx()]; + + // expected-error@+1{{cannot use 'ptr->buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_zero_ptr = &ptr->buf[0]; + // expected-error@+1{{cannot use 'ptr->buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_idx_ptr = &ptr->buf[idx()]; + // expected-error@+1{{cannot use 'ptr->buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_zero_ptr_typedef = &ptr->buf_typedef[0]; + // expected-error@+1{{cannot use 'ptr->buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + struct IncompleteTy* addr_elt_idx_ptr_typedef = &ptr->buf_typedef[idx()]; + + // =========================================================================== + // ## Use fields as call arguments + // =========================================================================== + // expected-error@+1{{cannot use 'uninit.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + consume_struct_IncompleteTy(uninit.buf); + // expected-error@+1{{cannot use 'uninit.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + consume_struct_IncompleteTy(uninit.buf_typedef); + // expected-error@+1{{cannot use 'ptr->buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + consume_struct_IncompleteTy(ptr->buf); + // expected-error@+1{{cannot use 'ptr->buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + consume_struct_IncompleteTy(ptr->buf_typedef); + + // =========================================================================== + // ## Use [] operator on fields + // =========================================================================== + // expected-error@+1 2{{cannot use 'uninit.buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + uninit.buf[0] = uninit.buf[1]; + // expected-error@+1 2{{cannot use 'uninit.buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + uninit.buf_typedef[0] = uninit.buf_typedef[1]; + // expected-error@+1 2{{cannot use 'ptr->buf' with type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + ptr->buf[0] = ptr->buf[1]; + // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + ptr->buf_typedef[0] = ptr->buf_typedef[1]; +} + +// ============================================================================= +// ## Global initialization +// ============================================================================= + +struct CBBufDeclPos global_explicit_desig_init = { + .count = 0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + .buf = 0x0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + .buf_typedef = 0x0 +}; + +void use_global_explicit_desig_init(void) { + // Variable isn't marked as invalid so diagnostics still fire + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + global_explicit_desig_init.buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + global_explicit_desig_init.buf_typedef = 0x0; +} + +struct CBBufDeclPos global_partial_explicit_desig_init = { + .count = 0, + // .buf and .buf_typedef are implicit zero initialized + // expected-error@+2{{cannot implicitly initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} +}; + +struct CBBufDeclPos global_implicit_full_init = { + 0 + // expected-error@+2{{cannot implicitly initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} +}; + +struct CBBufDeclPos global_explicit_non_desig_init = { + 0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf' that has type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy' or using the '__sized_by' attribute}} + 0x0, + // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' that has type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_t' or using the '__sized_by' attribute}} + 0x0 +}; + +extern struct CBBufDeclPos global_declaration; // OK + +// TODO: These tentative definitions are implicitly empty initialized to zero. +// This should generate an error diagnostic but currently doesn't. There should +// be a carve out to allow `__counted_by(0)` which is the only constant count +// version of the attribute where it is valid to assign NULL. +struct CBBufDeclPos global_tentative_defn; +static struct CBBufDeclPos global_tentative_defn2; + +// ============================================================================= +// ## Completing the definition of the type allows use of CBBufDeclPos fields +// ============================================================================= +struct IncompleteTy { + int field; +}; + +void test_CBBufDeclPos_completed(struct CBBufDeclPos* ptr) { + // Initialization is ok + struct CBBufDeclPos explicit_desig_init = { + .count = 0, + .buf = 0x0, + .buf_typedef = 0x0 + }; + + struct CBBufDeclPos partial_explicit_desig_init = { + .count = 0, + // .buf and .buf_typedef are implicit zero initialized + }; + + struct CBBufDeclPos implicit_full_init = {0}; + + struct CBBufDeclPos explicit_non_desig_init = { + 0, + 0x0, + 0x0 + }; + + // Assignment to fields is ok + ptr->buf = 0x0; + ptr->buf_typedef = 0x0; + + // Use of fields in expressions is ok + void* tmp = ptr->buf; + void* tmp2 = ptr->buf_typedef; + + // Take address of fields is ok + void* take_addr_ptr = &ptr->buf; + void* take_addr_ptr_typedef = &ptr->buf_typedef; + + struct IncompleteTy* addr_elt_zero_ptr = &ptr->buf[0]; + struct IncompleteTy* addr_elt_idx_ptr = &ptr->buf[idx()]; + struct IncompleteTy* addr_elt_zero_ptr_typedef = &ptr->buf_typedef[0]; + struct IncompleteTy* addr_elt_idx_ptr_typedef = &ptr->buf_typedef[idx()]; + + // As call arguments is ok + consume_struct_IncompleteTy(ptr->buf); + consume_struct_IncompleteTy(ptr->buf_typedef); + + // In [] operator is ok + ptr->buf[0] = ptr->buf[1]; + ptr->buf_typedef[0] = ptr->buf_typedef[1]; +} + +// Global initialization is ok + +struct CBBufDeclPos global_explicit_desig_init_completed = { + .count = 0, + .buf = 0x0, + .buf_typedef = 0x0 +}; + +struct CBBufDeclPos global_partial_explicit_desig_init_completed = { + .count = 0, + // .buf and .buf_typedef are implicit zero initialized +}; + +struct CBBufDeclPos global_implicit_full_init_completed = {0}; + +struct CBBufDeclPos global_explicit_non_desig_init_completed = { + 0, + 0x0, + 0x0 +}; + +extern struct CBBufDeclPos global_declaration; +struct CBBufDeclPos global_tentative_defn; +static struct CBBufDeclPos global_tentative_defn2; + +// ============================================================================= +// # Struct incomplete type with attribute in the pointer position +// ============================================================================= + +// expected-note@+1 8{{forward declaration of 'Incomplete_ty2' (aka 'struct IncompleteTy2')}} +struct IncompleteTy2; // expected-note 8{{forward declaration of 'struct IncompleteTy2'}} +typedef struct IncompleteTy2 Incomplete_ty2; + +void consume_struct_IncompleteTy2(struct IncompleteTy2* buf); + +struct CBBufTyPos { + int count; + struct IncompleteTy2* __counted_by(count) buf ; // OK expected-note 8{{__counted_by attribute is here}} + Incomplete_ty2 *__counted_by(count) buf_typedef; // OK expected-note 8{{__counted_by attribute is here}} +}; + +void use_CBBufTyPos(struct CBBufTyPos* ptr) { + struct CBBufTyPos explicit_desig_init = { + .count = 0, + // expected-error@+1{{cannot initialize 'CBBufTyPos::buf' that has type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + .buf = 0x0, + // expected-error@+1{{cannot initialize 'CBBufTyPos::buf_typedef' that has type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + .buf_typedef = 0x0 + }; + + // Assignment + // expected-error@+1{{cannot assign to 'CBBufTyPos::buf' that has type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + explicit_desig_init.buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufTyPos::buf_typedef' that has type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + explicit_desig_init.buf_typedef = 0x0; + // expected-error@+1{{cannot assign to 'CBBufTyPos::buf' that has type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + ptr->buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufTyPos::buf_typedef' that has type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + ptr->buf_typedef = 0x0; + + // Use + // expected-error@+2{{cannot use 'ptr->buf' with type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + void* addr = + ((char*) ptr->buf ) + 1; + // expected-error@+2{{cannot use 'ptr->buf_typedef' with type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + void* addr_typedef = + ((char*) ptr->buf_typedef ) + 1; + + // expected-error@+1{{cannot use 'ptr->buf' with type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + consume_struct_IncompleteTy2(ptr->buf); + // expected-error@+1{{cannot use 'ptr->buf_typedef' with type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + consume_struct_IncompleteTy2(ptr->buf_typedef); + + // expected-error@+1 2{{cannot use 'ptr->buf' with type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + ptr->buf[0] = ptr->buf[1]; + // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + ptr->buf_typedef[0] = ptr->buf_typedef[1]; +} + +struct CBBufTyPos global_explicit_desig_init_struct_type_pos = { + .count = 0, + // expected-error@+1{{cannot initialize 'CBBufTyPos::buf' that has type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'struct IncompleteTy2' or using the '__sized_by' attribute}} + .buf = 0x0, + // expected-error@+1{{cannot initialize 'CBBufTyPos::buf_typedef' that has type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'Incomplete_ty2' or using the '__sized_by' attribute}} + .buf_typedef = 0x0 +}; + +// Defining the type makes `CBBufTyPos` fields usable +struct IncompleteTy2 { + int field; +}; + +void use_CBBufTyPos_completed(struct CBBufTyPos* ptr) { + ptr->buf = 0x0; + ptr->buf_typedef = 0x0; + void* addr = ((char*) ptr->buf) + 1; + void* addr_typedef = ((char*) ptr->buf_typedef) + 1; +} + +// ============================================================================= +// # union incomplete type +// ============================================================================= + +// expected-note@+1 8{{forward declaration of 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy')}} +union IncompleteUnionTy; // expected-note 8{{forward declaration of 'union IncompleteUnionTy'}} +typedef union IncompleteUnionTy IncompleteUnion_ty; + +void consume_struct_IncompleteUnionTy(union IncompleteUnionTy* buf); + +struct CBBufUnionTyPos { + int count; + union IncompleteUnionTy* __counted_by(count) buf ; // OK expected-note 8{{__counted_by attribute is here}} + IncompleteUnion_ty *__counted_by(count) buf_typedef; // OK expected-note 8{{__counted_by attribute is here}} +}; + +void use_CBBufUnionTyPos(struct CBBufUnionTyPos* ptr) { + struct CBBufUnionTyPos explicit_desig_init = { + .count = 0, + // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf' that has type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + .buf = 0x0, + // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf_typedef' that has type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + .buf_typedef = 0x0 + }; + + // Assignment + // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf' that has type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + explicit_desig_init.buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf_typedef' that has type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + explicit_desig_init.buf_typedef = 0x0; + // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf' that has type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + ptr->buf = 0x0; + // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf_typedef' that has type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when assigning; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + ptr->buf_typedef = 0x0; + + // Use + // expected-error@+2{{cannot use 'ptr->buf' with type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + void* addr = + ((char*) ptr->buf ) + 1; + // expected-error@+2{{cannot use 'ptr->buf_typedef' with type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + void* addr_typedef = + ((char*) ptr->buf_typedef ) + 1; + + // expected-error@+1{{cannot use 'ptr->buf' with type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + consume_struct_IncompleteUnionTy(ptr->buf); + // expected-error@+1{{cannot use 'ptr->buf_typedef' with type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + consume_struct_IncompleteUnionTy(ptr->buf_typedef); + + // expected-error@+1 2{{cannot use 'ptr->buf' with type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + ptr->buf[0] = ptr->buf[1]; + // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete in this context; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + ptr->buf_typedef[0] = ptr->buf_typedef[1]; +} + +struct CBBufUnionTyPos global_explicit_desig_init_union_type_pos = { + .count = 0, + // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf' that has type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'union IncompleteUnionTy' or using the '__sized_by' attribute}} + .buf = 0x0, + // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf_typedef' that has type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete and the '__counted_by' attribute requires the pointee type be complete when initializing; consider providing a complete definition for 'IncompleteUnion_ty' or using the '__sized_by' attribute}} + .buf_typedef = 0x0 +}; + +// Defining the type makes `CBBufUnionTyPos` fields usable +union IncompleteUnionTy { + int field; +}; + +void use_CBBufUnionTyPos_completed(struct CBBufUnionTyPos* ptr) { + ptr->buf = 0x0; + ptr->buf_typedef = 0x0; + void* addr = ((char*) ptr->buf) + 1; + void* addr_typedef = ((char*) ptr->buf_typedef) + 1; +} + +// ============================================================================= +// # enum incomplete type +// ============================================================================= + +// expected-note@+1 8{{forward declaration of 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy')}} +enum IncompleteEnumTy; // expected-note 8{{forward declaration of 'enum IncompleteEnumTy'}} ---------------- Sirraide wrote:
Note that this is valid if we specify an explicit underlying type: ```c enum s : unsigned; enum s x; // Ok ``` I would expect that this already works as it should, but we should probably also have a test or two for that as well. https://github.com/llvm/llvm-project/pull/106321 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits