| // 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@+3 27{{consider providing a complete definition for 'Incomplete_t' (aka 'struct IncompleteTy')}} |
| // The 'forward declaration' notes come from 'arithmetic on a pointer to an incomplete type' errors |
| // expected-note@+1 24{{forward declaration of 'struct IncompleteTy'}} |
| struct IncompleteTy; // expected-note 27{{consider providing a complete definition for 'struct IncompleteTy'}} |
| |
| typedef struct IncompleteTy Incomplete_t; |
| |
| struct CBBufDeclPos { |
| int count; |
| struct IncompleteTy* buf __counted_by(count); // OK expected-note 27{{consider using '__sized_by' instead of '__counted_by'}} |
| Incomplete_t* buf_typedef __counted_by(count); // OK expected-note 27{{consider using '__sized_by' instead of '__counted_by'}} |
| }; |
| |
| 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' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| .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' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| explicit_desig_init.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| explicit_desig_init.buf_typedef = 0x0; |
| // expected-error@+1{{cannot use 'explicit_desig_init.buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| void *tmp = explicit_desig_init.buf; |
| // expected-error@+1{{cannot use 'explicit_desig_init.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 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' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| }; |
| |
| struct CBBufDeclPos implicit_full_init = { |
| 0 |
| // expected-error@+2{{cannot implicitly initialize 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| }; |
| // Variable is not currently marked as invalid so uses of the variable allows |
| // diagnostics to fire. |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| implicit_full_init.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| implicit_full_init.buf_typedef = 0x0; |
| // expected-error@+1{{cannot use 'implicit_full_init.buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| void* tmp3 = implicit_full_init.buf; |
| // expected-error@+1{{cannot use 'implicit_full_init.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| void* tmp4 = implicit_full_init.buf_typedef; |
| |
| struct CBBufDeclPos explicit_non_desig_init = { |
| 0, |
| // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 0x0 |
| }; |
| |
| |
| |
| |
| // =========================================================================== |
| // ## Assignment to fields |
| // =========================================================================== |
| struct CBBufDeclPos uninit; |
| uninit.count = 0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| uninit.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| uninit.buf_typedef = 0x0; |
| ptr->count = 0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| ptr->buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 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 '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| void* addr = |
| ((char*) uninit.buf ) + 1; |
| // expected-error@+2{{cannot use 'uninit.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| void* addr_typedef = |
| ((char*) uninit.buf_typedef ) + 1; |
| // expected-error@+2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| void* addr_ptr = |
| ((char*) ptr->buf ) + 1; |
| // expected-error@+2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 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 '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| struct IncompleteTy* addr_elt_zero = &uninit.buf[0]; |
| // expected-error@+1{{cannot use 'uninit.buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| struct IncompleteTy* addr_elt_idx = &uninit.buf[idx()]; |
| |
| // expected-error@+1{{cannot use 'uninit.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| struct IncompleteTy* addr_elt_zero_typedef = &uninit.buf_typedef[0]; |
| // expected-error@+1{{cannot use 'uninit.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| struct IncompleteTy* addr_elt_idx_typedef = &uninit.buf_typedef[idx()]; |
| |
| // expected-error@+1{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| struct IncompleteTy* addr_elt_zero_ptr = &ptr->buf[0]; |
| // expected-error@+1{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| struct IncompleteTy* addr_elt_idx_ptr = &ptr->buf[idx()]; |
| // expected-error@+1{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| struct IncompleteTy* addr_elt_zero_ptr_typedef = &ptr->buf_typedef[0]; |
| // expected-error@+1{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| struct IncompleteTy* addr_elt_idx_ptr_typedef = &ptr->buf_typedef[idx()]; |
| |
| |
| // =========================================================================== |
| // ## Use fields as call arguments |
| // =========================================================================== |
| // expected-error@+1{{cannot use 'uninit.buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| consume_struct_IncompleteTy(uninit.buf); |
| // expected-error@+1{{cannot use 'uninit.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| consume_struct_IncompleteTy(uninit.buf_typedef); |
| // expected-error@+1{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| consume_struct_IncompleteTy(ptr->buf); |
| // expected-error@+1{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| consume_struct_IncompleteTy(ptr->buf_typedef); |
| |
| // =========================================================================== |
| // ## Use [] operator on fields |
| // =========================================================================== |
| // expected-error@+1 2{{cannot use 'uninit.buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| uninit.buf[0] = uninit.buf[1]; |
| // expected-error@+1 2{{cannot use 'uninit.buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| uninit.buf_typedef[0] = uninit.buf_typedef[1]; |
| // expected-error@+1 2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| ptr->buf[0] = ptr->buf[1]; |
| // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 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' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| .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' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| global_explicit_desig_init.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 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' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| }; |
| |
| struct CBBufDeclPos global_implicit_full_init = { |
| 0 |
| // expected-error@+2{{cannot implicitly initialize 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| // expected-error@+1{{cannot implicitly initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| }; |
| |
| struct CBBufDeclPos global_explicit_non_desig_init = { |
| 0, |
| // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf' with '__counted_by' attributed type 'struct IncompleteTy * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'struct IncompleteTy' is incomplete}} |
| 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufDeclPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_t * __counted_by(count)' (aka 'struct IncompleteTy *') because the pointee type 'Incomplete_t' (aka 'struct IncompleteTy') is incomplete}} |
| 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{{consider providing a complete definition for 'Incomplete_ty2' (aka 'struct IncompleteTy2')}} |
| struct IncompleteTy2; // expected-note 8{{consider providing a complete definition for '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{{consider using '__sized_by' instead of '__counted_by'}} |
| Incomplete_ty2 *__counted_by(count) buf_typedef; // OK expected-note 8{{consider using '__sized_by' instead of '__counted_by'}} |
| }; |
| |
| void use_CBBufTyPos(struct CBBufTyPos* ptr) { |
| struct CBBufTyPos explicit_desig_init = { |
| .count = 0, |
| // expected-error@+1{{cannot initialize 'CBBufTyPos::buf' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufTyPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| .buf_typedef = 0x0 |
| }; |
| |
| // Assignment |
| // expected-error@+1{{cannot assign to 'CBBufTyPos::buf' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| explicit_desig_init.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufTyPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| explicit_desig_init.buf_typedef = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufTyPos::buf' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| ptr->buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufTyPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| ptr->buf_typedef = 0x0; |
| |
| // Use |
| // expected-error@+2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| void* addr = |
| ((char*) ptr->buf ) + 1; |
| // expected-error@+2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| void* addr_typedef = |
| ((char*) ptr->buf_typedef ) + 1; |
| |
| // expected-error@+1{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| consume_struct_IncompleteTy2(ptr->buf); |
| // expected-error@+1{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| consume_struct_IncompleteTy2(ptr->buf_typedef); |
| |
| // expected-error@+1 2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| ptr->buf[0] = ptr->buf[1]; |
| // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| 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' with '__counted_by' attributed type 'struct IncompleteTy2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'struct IncompleteTy2' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufTyPos::buf_typedef' with '__counted_by' attributed type 'Incomplete_ty2 * __counted_by(count)' (aka 'struct IncompleteTy2 *') because the pointee type 'Incomplete_ty2' (aka 'struct IncompleteTy2') is incomplete}} |
| .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{{consider providing a complete definition for 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy')}} |
| union IncompleteUnionTy; // expected-note 8{{consider providing a complete definition for '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{{consider using '__sized_by' instead of '__counted_by'}} |
| IncompleteUnion_ty *__counted_by(count) buf_typedef; // OK expected-note 8{{consider using '__sized_by' instead of '__counted_by'}} |
| }; |
| |
| void use_CBBufUnionTyPos(struct CBBufUnionTyPos* ptr) { |
| struct CBBufUnionTyPos explicit_desig_init = { |
| .count = 0, |
| // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| .buf_typedef = 0x0 |
| }; |
| |
| // Assignment |
| // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| explicit_desig_init.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| explicit_desig_init.buf_typedef = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| ptr->buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufUnionTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| ptr->buf_typedef = 0x0; |
| |
| // Use |
| // expected-error@+2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| void* addr = |
| ((char*) ptr->buf ) + 1; |
| // expected-error@+2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| void* addr_typedef = |
| ((char*) ptr->buf_typedef ) + 1; |
| |
| // expected-error@+1{{cannot use 'ptr->buf' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| consume_struct_IncompleteUnionTy(ptr->buf); |
| // expected-error@+1{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| consume_struct_IncompleteUnionTy(ptr->buf_typedef); |
| |
| // expected-error@+1 2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| ptr->buf[0] = ptr->buf[1]; |
| // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| 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' with '__counted_by' attributed type 'union IncompleteUnionTy * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'union IncompleteUnionTy' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufUnionTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteUnion_ty * __counted_by(count)' (aka 'union IncompleteUnionTy *') because the pointee type 'IncompleteUnion_ty' (aka 'union IncompleteUnionTy') is incomplete}} |
| .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{{consider providing a complete definition for 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy')}} |
| enum IncompleteEnumTy; // expected-note 8{{consider providing a complete definition for 'enum IncompleteEnumTy'}} |
| typedef enum IncompleteEnumTy IncompleteEnum_ty; |
| |
| void consume_struct_IncompleteEnumTy(enum IncompleteEnumTy* buf); |
| |
| struct CBBufEnumTyPos { |
| int count; |
| enum IncompleteEnumTy* __counted_by(count) buf ; // OK expected-note 8{{consider using '__sized_by' instead of '__counted_by'}} |
| IncompleteEnum_ty *__counted_by(count) buf_typedef; // OK expected-note 8{{consider using '__sized_by' instead of '__counted_by'}} |
| }; |
| |
| void use_CBBufEnumTyPos(struct CBBufEnumTyPos* ptr) { |
| struct CBBufEnumTyPos explicit_desig_init = { |
| .count = 0, |
| // expected-error@+1{{cannot initialize 'CBBufEnumTyPos::buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufEnumTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| .buf_typedef = 0x0 |
| }; |
| |
| // Assignment |
| // expected-error@+1{{cannot assign to 'CBBufEnumTyPos::buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| explicit_desig_init.buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufEnumTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| explicit_desig_init.buf_typedef = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufEnumTyPos::buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| ptr->buf = 0x0; |
| // expected-error@+1{{cannot assign to 'CBBufEnumTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| ptr->buf_typedef = 0x0; |
| |
| // Use |
| // expected-error@+2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| void* addr = |
| ((char*) ptr->buf ) + 1; |
| // expected-error@+2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| void* addr_typedef = |
| ((char*) ptr->buf_typedef ) + 1; |
| |
| // expected-error@+1{{cannot use 'ptr->buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| consume_struct_IncompleteEnumTy(ptr->buf); |
| // expected-error@+1{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| consume_struct_IncompleteEnumTy(ptr->buf_typedef); |
| |
| // expected-error@+1 2{{cannot use 'ptr->buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| ptr->buf[0] = ptr->buf[1]; |
| // expected-error@+1 2{{cannot use 'ptr->buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| ptr->buf_typedef[0] = ptr->buf_typedef[1]; |
| } |
| |
| struct CBBufEnumTyPos global_explicit_desig_init_enum_type_pos = { |
| .count = 0, |
| // expected-error@+1{{cannot initialize 'CBBufEnumTyPos::buf' with '__counted_by' attributed type 'enum IncompleteEnumTy * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'enum IncompleteEnumTy' is incomplete}} |
| .buf = 0x0, |
| // expected-error@+1{{cannot initialize 'CBBufEnumTyPos::buf_typedef' with '__counted_by' attributed type 'IncompleteEnum_ty * __counted_by(count)' (aka 'enum IncompleteEnumTy *') because the pointee type 'IncompleteEnum_ty' (aka 'enum IncompleteEnumTy') is incomplete}} |
| .buf_typedef = 0x0 |
| }; |
| |
| // Defining the type makes `CBBufEnumTyPos` fields usable |
| enum IncompleteEnumTy { |
| ONE, |
| TWO |
| }; |
| |
| void use_CBBufEnumTyPos_completed(struct CBBufEnumTyPos* ptr) { |
| ptr->buf = 0x0; |
| ptr->buf_typedef = 0x0; |
| void* addr = ((char*) ptr->buf) + 1; |
| void* addr_typedef = ((char*) ptr->buf_typedef) + 1; |
| } |
| |
| // Make a complete enum by providing an underlying type |
| enum CompleteEnumTy : unsigned; |
| typedef enum CompleteEnumTy CompleteEnum_ty; |
| struct CBBufEnumTyPos2 { |
| int count; |
| enum CompleteEnumTy* __counted_by(count) buf; |
| CompleteEnum_ty *__counted_by(count) buf_typedef; |
| }; |
| |
| void use_CBBufEnumTyPos2(struct CBBufEnumTyPos2* ptr) { |
| struct CBBufEnumTyPos2 explicit_desig_init = { |
| .count = 0, |
| .buf = 0x0, // OK |
| .buf_typedef = 0x0 // OK |
| }; |
| } |
| |
| // Make a complete enum by providing a concrete declaration |
| enum CompleteEnumTy2 { |
| VALUE_ONE, |
| VALUE_TWO |
| }; |
| typedef enum CompleteEnumTy2 CompleteEnum_ty2; |
| struct CBBufEnumTyPos3 { |
| int count; |
| enum CompleteEnumTy2* __counted_by(count) buf; |
| CompleteEnum_ty2 *__counted_by(count) buf_typedef; |
| }; |
| |
| void use_CBBufEnumTyPos3(struct CBBufEnumTyPos3* ptr) { |
| struct CBBufEnumTyPos3 explicit_desig_init = { |
| .count = 0, |
| .buf = 0x0, // OK |
| .buf_typedef = 0x0 // OK |
| }; |
| } |
| |
| |
| // ============================================================================= |
| // # Array of __counted_by pointers |
| // ============================================================================= |
| |
| struct IncompleteTy3; |
| |
| struct CBBufFAMofCountedByPtrs { |
| int size; |
| // TODO: This is misleading. The attribute is written in the type position |
| // but clang currently doesn't treat it like that and it gets treated as |
| // an attribute on the array, rather than on the element type. |
| struct IncompleteTy3* __counted_by(size) arr[]; |
| }; |
| |
| void arr_of_counted_by_ptr(struct CBBufFAMofCountedByPtrs* ptr) { |
| // TODO: Should be disallowed once parsing attributes in the type position |
| // works. |
| ptr->arr[0] = 0x0; |
| void* addr = ((char*) ptr->arr[0]) + 1; |
| } |