[clang] [BoundsSafety][Sema] Allow counted_by and counted_by_or_null on pointers where the pointee type is incomplete but potentially completable (PR #106321)

via cfe-commits cfe-commits at lists.llvm.org
Thu Oct 24 23:06:46 PDT 2024


================
@@ -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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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 at +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


More information about the cfe-commits mailing list