https://github.com/rapidsna created 
https://github.com/llvm/llvm-project/pull/224553

New tests exercising the late-parse fill-in mechanism:
  - Sema/attr-counted-by-weird-type-positions{,-late-parsed}.c: counted_by
    in assorted type positions, nested pointers, and rejection cases.
  - Sema/attr-bounds-safety-function-ptr-param.c: attributes on
    function-pointer-typed members.
  - Modules/ and PCH/ bounds-safety-attributed-type-late-parsed: the
    resolved type round-trips through serialization.

  - Sema/attr-counted-by-late-parsed-regressions.c: guards against the
    double-free on a nested-record decl-spec attribute and the null-count
    escape on a free-function parameter.


>From 58357e47b000de946cbb4494ecb052619f9fbb17 Mon Sep 17 00:00:00 2001
From: Yeoul Na <[email protected]>
Date: Wed, 9 Sep 2026 13:02:47 -0700
Subject: [PATCH] [BoundsSafety][test] Add late-parsed counted_by
 type-attribute coverage

New tests exercising the late-parse fill-in mechanism:
  - Sema/attr-counted-by-weird-type-positions{,-late-parsed}.c: counted_by
    in assorted type positions, nested pointers, and rejection cases.
  - Sema/attr-bounds-safety-function-ptr-param.c: attributes on
    function-pointer-typed members.
  - Modules/ and PCH/ bounds-safety-attributed-type-late-parsed: the
    resolved type round-trips through serialization.

  - Sema/attr-counted-by-late-parsed-regressions.c: guards against the
    double-free on a nested-record decl-spec attribute and the null-count
    escape on a free-function parameter.
---
 .../AST/attr-counted-by-eager-invalid-strip.c |  27 ++
 ...-counted-by-late-parsed-invalid-recovery.c |  46 ++
 .../attr-counted-by-late-parsed-struct-ptrs.c |  19 +
 ...ounds-safety-attributed-type-late-parsed.c | 111 +++++
 ...ounds-safety-attributed-type-late-parsed.h |  58 +++
 ...ounds-safety-attributed-type-late-parsed.c |  69 +++
 .../attr-bounds-safety-function-ptr-param.c   | 173 +++++++
 .../attr-counted-by-late-parsed-regressions.c |  92 ++++
 ...nted-by-weird-type-positions-late-parsed.c | 456 ++++++++++++++++++
 .../attr-counted-by-weird-type-positions.c    | 454 +++++++++++++++++
 10 files changed, 1505 insertions(+)
 create mode 100644 clang/test/AST/attr-counted-by-eager-invalid-strip.c
 create mode 100644 
clang/test/AST/attr-counted-by-late-parsed-invalid-recovery.c
 create mode 100644 
clang/test/Modules/bounds-safety-attributed-type-late-parsed.c
 create mode 100644 
clang/test/PCH/Inputs/bounds-safety-attributed-type-late-parsed.h
 create mode 100644 clang/test/PCH/bounds-safety-attributed-type-late-parsed.c
 create mode 100644 clang/test/Sema/attr-bounds-safety-function-ptr-param.c
 create mode 100644 clang/test/Sema/attr-counted-by-late-parsed-regressions.c
 create mode 100644 
clang/test/Sema/attr-counted-by-weird-type-positions-late-parsed.c
 create mode 100644 clang/test/Sema/attr-counted-by-weird-type-positions.c

diff --git a/clang/test/AST/attr-counted-by-eager-invalid-strip.c 
b/clang/test/AST/attr-counted-by-eager-invalid-strip.c
new file mode 100644
index 0000000000000..51cd306aa1970
--- /dev/null
+++ b/clang/test/AST/attr-counted-by-eager-invalid-strip.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -verify %s -ast-dump | FileCheck %s
+
+// On the eager (non -fexperimental-late-parse-attributes) path a
+// counted_by-family CountAttributedType is built during type processing, 
before
+// the FieldDecl-dependent checks run in ActOnFields. When those checks reject
+// the attribute, the CountAttributedType must be stripped so the field keeps
+// its plain wrapped type -- matching the pre-refactor behavior, which built 
the
+// type only after the check passed. A surviving bogus CountAttributedType 
would
+// otherwise flow downstream. This test pins the stripped type; the diagnostics
+// themselves are covered elsewhere.
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+union invalid_union_member {
+  int n;
+  int *__counted_by(n) p; // expected-error {{'counted_by' cannot be applied 
to a union member}}
+};
+// CHECK-LABEL: union invalid_union_member definition
+// CHECK: FieldDecl {{.*}} p 'int *'{{$}}
+
+struct invalid_non_fam_array {
+  int n;
+  int arr[10] __counted_by(n); // expected-error {{'counted_by' on arrays only 
applies to C99 flexible array members}}
+  int last;
+};
+// CHECK-LABEL: struct invalid_non_fam_array definition
+// CHECK: FieldDecl {{.*}} arr 'int[10]'{{$}}
diff --git a/clang/test/AST/attr-counted-by-late-parsed-invalid-recovery.c 
b/clang/test/AST/attr-counted-by-late-parsed-invalid-recovery.c
new file mode 100644
index 0000000000000..776f8422ad0fc
--- /dev/null
+++ b/clang/test/AST/attr-counted-by-late-parsed-invalid-recovery.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -verify %s -ast-dump | 
FileCheck %s
+
+// On the late-parsed path the CountAttributedType is built before its count
+// argument is parsed, so a rejected argument is only discovered at completion,
+// when the node is already embedded in the field's type. Rather than strip a
+// (possibly nested) node -- which would force the enclosing types to be 
rebuilt
+// -- the node is kept and completed in place with the raw argument, and the
+// field is marked invalid. Consumers bail on such a count (see
+// FieldDecl::findCountedByField). This applies whether the argument is 
unusable
+// (a parse failure, or a non-declaration-reference such as `sizeof(...)`) or 
is
+// a valid reference in an invalid position (a union member).
+//
+// A nested counted_by is the exception: it is diagnosed and dropped while the
+// declarator is built -- before the enclosing pointer/array wraps the node, so
+// the drop needs no rebuild -- leaving the field its plain wrapped type, 
exactly
+// as on the eager path.
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+// Non-declaration-reference argument: the node is kept with the raw argument 
as
+// its count and the field is marked invalid.
+struct bad_count_expr {
+  int n;
+  int *__counted_by(sizeof(int)) p; // expected-error {{'counted_by' argument 
must be a simple declaration reference}}
+};
+// CHECK-LABEL: struct bad_count_expr definition
+// CHECK: FieldDecl {{.*}} invalid p 'int * __counted_by(sizeof(int))':'int *'
+
+// Valid reference in an invalid position: also kept with the raw argument and
+// the field marked invalid.
+union valid_ref_bad_position {
+  int n;
+  int *__counted_by(n) p; // expected-error {{'counted_by' cannot be applied 
to a union member}}
+};
+// CHECK-LABEL: union valid_ref_bad_position definition
+// CHECK: FieldDecl {{.*}} invalid p 'int * __counted_by(n)':'int *'
+
+// Nested under another pointer: diagnosed and dropped while the declarator is
+// built, so the field keeps its plain wrapped type (no CountAttributedType) 
and
+// stays valid -- exactly as on the eager path.
+struct nested_under_pointer {
+  int n;
+  int *__counted_by(n) *pp; // expected-error {{'counted_by' attribute on 
nested pointer type is not allowed}}
+};
+// CHECK-LABEL: struct nested_under_pointer definition
+// CHECK: FieldDecl {{.*}} pp 'int **'{{$}}
diff --git a/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c 
b/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c
index f9772db8b6554..9d43523bf3180 100644
--- a/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c
+++ b/clang/test/AST/attr-counted-by-late-parsed-struct-ptrs.c
@@ -43,3 +43,22 @@ struct on_pointer_anon_count {
 //
 // See `clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c` for test
 // cases.
+
+//==============================================================================
+// A declaration-specifier-position attribute shared by several declarators
+//==============================================================================
+// All declarators share one CountAttributedType, so every field must print a
+// resolved count. Previously only the last one did: each declarator built its
+// own (un-uniqued) node and only the last was ever completed, leaving the
+// earlier fields with an empty '__counted_by()'.
+
+typedef int *ptr_ty;
+
+struct shared_declspec_attr {
+  int count;
+  ptr_ty __counted_by(count) a, b;
+};
+// CHECK-LABEL: struct shared_declspec_attr definition
+// CHECK-NEXT:  |-FieldDecl {{.*}} referenced count 'int'
+// CHECK-NEXT:  |-FieldDecl {{.*}} a 'ptr_ty __counted_by(count)':'int *'
+// CHECK-NEXT:  `-FieldDecl {{.*}} b 'ptr_ty __counted_by(count)':'int *'
diff --git a/clang/test/Modules/bounds-safety-attributed-type-late-parsed.c 
b/clang/test/Modules/bounds-safety-attributed-type-late-parsed.c
new file mode 100644
index 0000000000000..58df0761f2022
--- /dev/null
+++ b/clang/test/Modules/bounds-safety-attributed-type-late-parsed.c
@@ -0,0 +1,111 @@
+// Test serialization of late-parsed bounds-safety attributes via Modules
+// This verifies that LateParsedAttrType is transformed to CountAttributedType
+// before serialization and remains as CountAttributedType after 
deserialization.
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fmodules 
-fmodules-cache-path=%t -verify %s
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fmodules 
-fmodules-cache-path=%t -ast-dump-all %s | FileCheck %s
+// expected-no-diagnostics
+
+#pragma clang module build bounds_safety_late_parsed
+module bounds_safety_late_parsed {}
+#pragma clang module contents
+#pragma clang module begin bounds_safety_late_parsed
+
+// Test where counted_by references a field declared later
+struct LateRefPointer {
+  int *__attribute__((counted_by(count))) buf;
+  int count;
+};
+
+// Test with sized_by referencing later field
+struct LateRefSized {
+  int *__attribute__((sized_by(size))) data;
+  int size;
+};
+
+// Test with counted_by_or_null referencing later field
+struct LateRefCountedByOrNull {
+  int *__attribute__((counted_by_or_null(count))) buf;
+  int count;
+};
+
+// Test with sized_by_or_null referencing later field
+struct LateRefSizedByOrNull {
+  int *__attribute__((sized_by_or_null(size))) data;
+  int size;
+};
+
+// Test with nested struct
+struct LateRefNested {
+  struct Inner {
+    int value;
+  } *__attribute__((counted_by(n))) items;
+  int n;
+};
+
+// Test with multiple late-parsed attributes
+struct MultipleLateRefs {
+  int *__attribute__((counted_by(count1))) buf1;
+  int *__attribute__((sized_by(count2))) buf2;
+  int *__attribute__((counted_by_or_null(count3))) buf3;
+  int *__attribute__((sized_by_or_null(count4))) buf4;
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+};
+
+#pragma clang module end
+#pragma clang module endbuild
+
+#pragma clang module import bounds_safety_late_parsed
+
+struct LateRefPointer *p1;
+struct LateRefSized *p2;
+struct LateRefCountedByOrNull *p3;
+struct LateRefSizedByOrNull *p4;
+struct LateRefNested *p5;
+struct MultipleLateRefs *p6;
+
+// CHECK: RecordDecl {{.*}} imported in bounds_safety_late_parsed 
<undeserialized declarations> struct LateRefPointer definition
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed buf 
'int * __counted_by(count)':'int *'
+// CHECK-NEXT: `-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced count 'int'
+
+// CHECK: RecordDecl {{.*}} imported in bounds_safety_late_parsed 
<undeserialized declarations> struct LateRefSized definition
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed data 
'int * __sized_by(size)':'int *'
+// CHECK-NEXT: `-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced size 'int'
+
+// CHECK: RecordDecl {{.*}} imported in bounds_safety_late_parsed 
<undeserialized declarations> struct LateRefCountedByOrNull definition
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed buf 
'int * __counted_by_or_null(count)':'int *'
+// CHECK-NEXT: `-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced count 'int'
+
+// CHECK: RecordDecl {{.*}} imported in bounds_safety_late_parsed 
<undeserialized declarations> struct LateRefSizedByOrNull definition
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed data 
'int * __sized_by_or_null(size)':'int *'
+// CHECK-NEXT: `-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced size 'int'
+
+// CHECK: RecordDecl {{.*}} imported in bounds_safety_late_parsed 
<undeserialized declarations> struct LateRefNested definition
+// CHECK: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed items 
'struct Inner * __counted_by(n)':'struct Inner *'
+// CHECK: `-FieldDecl {{.*}} imported in bounds_safety_late_parsed referenced 
n 'int'
+
+// CHECK: RecordDecl {{.*}} imported in bounds_safety_late_parsed 
<undeserialized declarations> struct MultipleLateRefs definition
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed buf1 
'int * __counted_by(count1)':'int *'
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed buf2 
'int * __sized_by(count2)':'int *'
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed buf3 
'int * __counted_by_or_null(count3)':'int *'
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed buf4 
'int * __sized_by_or_null(count4)':'int *'
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced count1 'int'
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced count2 'int'
+// CHECK-NEXT: |-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced count3 'int'
+// CHECK-NEXT: `-FieldDecl {{.*}} imported in bounds_safety_late_parsed 
referenced count4 'int'
+
+// Verify that LateParsedAttrType does not appear in the AST dump
+// CHECK-NOT: LateParsedAttr
+
+// Verify the import and variable declarations
+// CHECK: ImportDecl {{.*}} implicit bounds_safety_late_parsed
+// CHECK: VarDecl {{.*}} p1 'struct LateRefPointer *'
+// CHECK: VarDecl {{.*}} p2 'struct LateRefSized *'
+// CHECK: VarDecl {{.*}} p3 'struct LateRefCountedByOrNull *'
+// CHECK: VarDecl {{.*}} p4 'struct LateRefSizedByOrNull *'
+// CHECK: VarDecl {{.*}} p5 'struct LateRefNested *'
+// CHECK: VarDecl {{.*}} p6 'struct MultipleLateRefs *'
diff --git a/clang/test/PCH/Inputs/bounds-safety-attributed-type-late-parsed.h 
b/clang/test/PCH/Inputs/bounds-safety-attributed-type-late-parsed.h
new file mode 100644
index 0000000000000..c0751408045c7
--- /dev/null
+++ b/clang/test/PCH/Inputs/bounds-safety-attributed-type-late-parsed.h
@@ -0,0 +1,58 @@
+// Header for testing late-parsed bounds-safety attributes serialization
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+#define __sized_by(f)  __attribute__((sized_by(f)))
+#define __counted_by_or_null(f)  __attribute__((counted_by_or_null(f)))
+#define __sized_by_or_null(f)  __attribute__((sized_by_or_null(f)))
+
+// Test where counted_by references a field declared later
+struct LateRefPointer {
+  int *__counted_by(count) buf;
+  int count;
+};
+
+// Test with sized_by referencing later field
+struct LateRefSized {
+  int *__sized_by(size) data;
+  int size;
+};
+
+// Test with counted_by_or_null referencing later field
+struct LateRefCountedByOrNull {
+  int *__counted_by_or_null(count) buf;
+  int count;
+};
+
+// Test with sized_by_or_null referencing later field
+struct LateRefSizedByOrNull {
+  int *__sized_by_or_null(size) data;
+  int size;
+};
+
+// Test with nested struct
+struct LateRefNested {
+  struct Inner {
+    int value;
+  } *__counted_by(n) items;
+  int n;
+};
+
+// Test with multiple late-parsed attributes
+struct MultipleLateRefs {
+  int *__counted_by(count1) buf1;
+  int *__sized_by(count2) buf2;
+  int *__counted_by_or_null(count3) buf3;
+  int *__sized_by_or_null(count4) buf4;
+  int count1;
+  int count2;
+  int count3;
+  int count4;
+};
+
+// Test with anonymous struct/union
+struct LateRefAnon {
+  int *__counted_by(count) buf;
+  struct {
+    int count;
+  };
+};
diff --git a/clang/test/PCH/bounds-safety-attributed-type-late-parsed.c 
b/clang/test/PCH/bounds-safety-attributed-type-late-parsed.c
new file mode 100644
index 0000000000000..1d77bbe13927c
--- /dev/null
+++ b/clang/test/PCH/bounds-safety-attributed-type-late-parsed.c
@@ -0,0 +1,69 @@
+// Test serialization of late-parsed bounds-safety attributes via PCH
+// This verifies that LateParsedAttrType is transformed to CountAttributedType
+// before serialization and remains as CountAttributedType after 
deserialization.
+
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -include 
%S/Inputs/bounds-safety-attributed-type-late-parsed.h -fsyntax-only -verify %s
+
+// Test with pch.
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -emit-pch -o %t 
%S/Inputs/bounds-safety-attributed-type-late-parsed.h
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -include-pch %t 
-fsyntax-only -verify %s
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -include-pch %t 
-ast-print %s | FileCheck %s --check-prefix PRINT
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -include-pch %t 
-ast-dump-all %s | FileCheck %s --check-prefix DUMP
+// expected-no-diagnostics
+
+// PRINT: struct LateRefPointer {
+// PRINT-NEXT:     int * __counted_by(count)buf;
+// PRINT-NEXT:     int count;
+// PRINT-NEXT: };
+
+// PRINT: struct LateRefSized {
+// PRINT-NEXT:     int * __sized_by(size)data;
+// PRINT-NEXT:     int size;
+// PRINT-NEXT: };
+
+// PRINT: struct LateRefCountedByOrNull {
+// PRINT-NEXT:     int * __counted_by_or_null(count)buf;
+// PRINT-NEXT:     int count;
+// PRINT-NEXT: };
+
+// PRINT: struct LateRefSizedByOrNull {
+// PRINT-NEXT:     int * __sized_by_or_null(size)data;
+// PRINT-NEXT:     int size;
+// PRINT-NEXT: };
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
LateRefPointer definition
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf 'int * __counted_by(count)':'int 
*'
+// DUMP-NEXT: `-FieldDecl {{.*}} imported referenced count 'int'
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
LateRefSized definition
+// DUMP-NEXT: |-FieldDecl {{.*}} imported data 'int * __sized_by(size)':'int *'
+// DUMP-NEXT: `-FieldDecl {{.*}} imported referenced size 'int'
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
LateRefCountedByOrNull definition
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf 'int * 
__counted_by_or_null(count)':'int *'
+// DUMP-NEXT: `-FieldDecl {{.*}} imported referenced count 'int'
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
LateRefSizedByOrNull definition
+// DUMP-NEXT: |-FieldDecl {{.*}} imported data 'int * 
__sized_by_or_null(size)':'int *'
+// DUMP-NEXT: `-FieldDecl {{.*}} imported referenced size 'int'
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
LateRefNested definition
+// DUMP: |-FieldDecl {{.*}} imported items 'struct Inner * 
__counted_by(n)':'struct Inner *'
+// DUMP: `-FieldDecl {{.*}} imported referenced n 'int'
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
MultipleLateRefs definition
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf1 'int * 
__counted_by(count1)':'int *'
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf2 'int * __sized_by(count2)':'int 
*'
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf3 'int * 
__counted_by_or_null(count3)':'int *'
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf4 'int * 
__sized_by_or_null(count4)':'int *'
+// DUMP-NEXT: |-FieldDecl {{.*}} imported referenced count1 'int'
+// DUMP-NEXT: |-FieldDecl {{.*}} imported referenced count2 'int'
+// DUMP-NEXT: |-FieldDecl {{.*}} imported referenced count3 'int'
+// DUMP-NEXT: `-FieldDecl {{.*}} imported referenced count4 'int'
+
+// DUMP: RecordDecl {{.*}} imported <undeserialized declarations> struct 
LateRefAnon definition
+// DUMP-NEXT: |-FieldDecl {{.*}} imported buf 'int * __counted_by(count)':'int 
*'
+// DUMP: `-IndirectFieldDecl {{.*}} imported implicit referenced count 'int'
+
+// Verify that LateParsedAttrType does not appear in the AST dump
+// DUMP-NOT: LateParsedAttr
diff --git a/clang/test/Sema/attr-bounds-safety-function-ptr-param.c 
b/clang/test/Sema/attr-bounds-safety-function-ptr-param.c
new file mode 100644
index 0000000000000..091220e313958
--- /dev/null
+++ b/clang/test/Sema/attr-bounds-safety-function-ptr-param.c
@@ -0,0 +1,173 @@
+// XFAIL: *
+// FIXME: https://github.com/llvm/llvm-project/issues/166454
+
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify 
%s
+
+#define __counted_by(N) __attribute__((counted_by(N)))
+#define __counted_by_or_null(N) __attribute__((counted_by_or_null(N)))
+#define __sized_by(N) __attribute__((sized_by(N)))
+#define __sized_by_or_null(N) __attribute__((sized_by_or_null(N)))
+
+//==============================================================================
+// Test bounds safety attributes on function pointer parameters
+//==============================================================================
+
+struct counted_by_function_pointer_param {
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by(len));
+  int len;
+};
+
+struct counted_by_or_null_function_pointer_param {
+  // expected-error@+1{{'counted_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by_or_null(len));
+  int len;
+};
+
+struct sized_by_function_pointer_param {
+  // expected-error@+1{{'sized_by' attribute cannot be applied to a parameter 
in a function pointer type}}
+  int (*callback)(char *__sized_by(len));
+  int len;
+};
+
+struct sized_by_or_null_function_pointer_param {
+  // expected-error@+1{{'sized_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(char *__sized_by_or_null(len));
+  int len;
+};
+
+//==============================================================================
+// Test multiple parameters with bounds safety attributes
+//==============================================================================
+
+struct multiple_params_with_bounds_safety {
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*multi_callback)(int *__counted_by(len1), char *data, int len1);
+  int len1;
+};
+
+struct mixed_bounds_safety_params {
+  // expected-error@+2{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  // expected-error@+1{{'sized_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*mixed_callback)(int *__counted_by(count), char 
*__sized_by_or_null(size), int count, int size);
+  int count;
+  int size;
+};
+
+//==============================================================================
+// Test cases that do not require late parsing (count field defined before use)
+//==============================================================================
+
+struct counted_by_no_late_parse {
+  int len;
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by(len));
+};
+
+struct counted_by_or_null_no_late_parse {
+  int len;
+  // expected-error@+1{{'counted_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by_or_null(len));
+};
+
+struct sized_by_no_late_parse {
+  int len;
+  // expected-error@+1{{'sized_by' attribute cannot be applied to a parameter 
in a function pointer type}}
+  int (*callback)(char *__sized_by(len));
+};
+
+struct sized_by_or_null_no_late_parse {
+  int len;
+  // expected-error@+1{{'sized_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(char *__sized_by_or_null(len));
+};
+
+//==============================================================================
+// Test nested function pointer types
+//==============================================================================
+
+struct nested_function_pointer_with_bounds_safety {
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*outer_callback)(int (*inner)(int *__counted_by(len)), int len);
+  int len;
+};
+
+//==============================================================================
+// Test struct members with anonymous structs/unions (no late parsing needed)
+//==============================================================================
+
+struct with_anonymous_struct_no_late_parse {
+  int len;
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by(len));
+};
+
+struct with_anonymous_union_no_late_parse {
+  union {
+    int len;
+    float f_len;
+  };
+  // expected-error@+1{{'counted_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by_or_null(len));
+};
+
+//==============================================================================
+// Test with different parameter positions
+//==============================================================================
+
+struct first_param_bounds_safety_no_late_parse {
+  int count;
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int *__counted_by(count), void *data, int extra);
+};
+
+struct middle_param_bounds_safety_no_late_parse {
+  int size;
+  // expected-error@+1{{'sized_by' attribute cannot be applied to a parameter 
in a function pointer type}}
+  int (*callback)(void *prefix, char *__sized_by(size), int suffix);
+};
+
+struct last_param_bounds_safety_no_late_parse {
+  int len;
+  // expected-error@+1{{'counted_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(int a, float b, int *__counted_by_or_null(len));
+};
+
+//==============================================================================
+// Test with const and volatile qualifiers
+//==============================================================================
+
+struct const_param_bounds_safety_no_late_parse {
+  int count;
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(const int *__counted_by(count));
+};
+
+struct volatile_param_bounds_safety_no_late_parse {
+  int size;
+  // expected-error@+1{{'sized_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(volatile char *__sized_by_or_null(size));
+};
+
+struct const_volatile_param_bounds_safety_no_late_parse {
+  int len;
+  // expected-error@+1{{'counted_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback)(const volatile int *__counted_by_or_null(len));
+};
+
+//==============================================================================
+// Test with multiple function pointers in same struct
+//==============================================================================
+
+struct multiple_function_pointers_no_late_parse {
+  int len1, len2, size1, size2;
+  // expected-error@+1{{'counted_by' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback1)(int *__counted_by(len1));
+  // expected-error@+1{{'counted_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  int (*callback2)(int *__counted_by_or_null(len2));
+  // expected-error@+1{{'sized_by' attribute cannot be applied to a parameter 
in a function pointer type}}
+  void (*callback3)(char *__sized_by(size1));
+  // expected-error@+1{{'sized_by_or_null' attribute cannot be applied to a 
parameter in a function pointer type}}
+  void (*callback4)(char *__sized_by_or_null(size2));
+};
diff --git a/clang/test/Sema/attr-counted-by-late-parsed-regressions.c 
b/clang/test/Sema/attr-counted-by-late-parsed-regressions.c
new file mode 100644
index 0000000000000..cb1cca4d95d48
--- /dev/null
+++ b/clang/test/Sema/attr-counted-by-late-parsed-regressions.c
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify 
%s
+
+#define __counted_by(N) __attribute__((counted_by(N)))
+
+// A late-parsed type attribute in declarator-specifier position after a nested
+// record definition used to be registered both in the enclosing record's
+// field-attribute list and in its late-parsed-type-attribute list, so its
+// cached tokens were parsed and freed twice -- an assertion / use-after-free.
+// The point of this test is that it no longer crashes.
+//
+// FIXME: 'counted_by' on a non-pointer (here struct-typed) field should be
+// diagnosed as "only applies to pointers or C99 flexible array members"; the
+// late path currently accepts it silently. That missing diagnostic is a
+// separate issue from the double-free guarded here.
+struct nested_record_declspec_attr {
+  struct inner1 {
+    int x;
+    int *p;
+  } __counted_by(x) f;
+  int y;
+};
+
+// A 'counted_by' type attribute on a free-function parameter has no enclosing
+// record to complete it. Late-parsing it left a CountAttributedType with a
+// null count expression in the AST, which crashed on serialization / PCH
+// round-trip. Parameters now fall back to eager handling, so the attribute is
+// resolved (or rejected) immediately instead of escaping unfinished.
+
+// Forward reference: eager handling can't see 'n' yet, so it is diagnosed
+// rather than silently building a null-count type.
+void fwd_ref_param(int *__counted_by(n) p, // expected-error {{use of 
undeclared identifier 'n'}}
+                   int n);
+
+// FIXME: counted_by on a function parameter isn't supported yet; the eager
+// decl-attribute path rejects it. What matters for this regression is that it
+// is diagnosed here, not left as an unfinished type for a later crash.
+void bwd_ref_param(int n,
+                   int *__counted_by(n) p); // expected-error {{'counted_by' 
attribute only applies to non-static data members}}
+
+// A declaration-specifier-position attribute is shared by every declarator in
+// the declaration, and ConvertDeclSpecToType walks the DeclSpec's 
late-attribute
+// list once per declarator. Building a fresh (deliberately un-uniqued)
+// CountAttributedType on each walk left every field but the last holding a 
node
+// whose count expression was never filled in -- silently, with no diagnostic 
--
+// and any use of such a field then tripped FieldDecl::findCountedByField's
+// unconditional cast<DeclRefExpr>. The attribute now reuses one node for all
+// declarators, matching the eager path where uniquing has the same effect.
+typedef int *shared_ptr_ty;
+
+struct shared_declspec_attr {
+  int n;
+  shared_ptr_ty __counted_by(n) a, b, c;
+};
+
+// Exercising the *earlier* declarators is the point: 'c' was always fine.
+void use_shared_declspec_attr(struct shared_declspec_attr *s) {
+  (void)__builtin_counted_by_ref(s->a);
+  (void)__builtin_counted_by_ref(s->b);
+  (void)__builtin_counted_by_ref(s->c);
+}
+
+// The same, with the count declared after the fields, so the attribute really 
is
+// late parsed rather than resolved eagerly.
+struct shared_declspec_attr_fwd {
+  shared_ptr_ty __counted_by(n) a, b;
+  int n;
+};
+
+void use_shared_declspec_attr_fwd(struct shared_declspec_attr_fwd *s) {
+  (void)__builtin_counted_by_ref(s->a);
+}
+
+// Each field is still checked in its own declaration context, so a shared
+// attribute reports once per field rather than once per attribute.
+union shared_declspec_attr_in_union {
+  int n;
+  // expected-error@+2 {{'counted_by' cannot be applied to a union member}}
+  // expected-error@+1 {{'counted_by' cannot be applied to a union member}}
+  shared_ptr_ty __counted_by(n) a, b;
+};
+
+// A grouping-paren declarator whose base type is already a pointer/array (via 
a
+// typedef) used to late-parse the attribute even at file scope, where there is
+// no enclosing record to complete it -- leaving a CountAttributedType with a
+// null count expression in the AST (and skipping the "non-static data members"
+// diagnostic entirely). ParseParenDeclarator now late-parses only inside a
+// record, so at file scope the attribute is handled eagerly and rejected.
+typedef int *ptr_ty;
+typedef int arr_ty[4];
+int global_count;
+ptr_ty (__counted_by(global_count) file_ptr); // expected-error {{'counted_by' 
attribute only applies to non-static data members}}
+arr_ty (__counted_by(global_count) file_arr); // expected-error {{'counted_by' 
attribute only applies to non-static data members}}
diff --git a/clang/test/Sema/attr-counted-by-weird-type-positions-late-parsed.c 
b/clang/test/Sema/attr-counted-by-weird-type-positions-late-parsed.c
new file mode 100644
index 0000000000000..0728c8623c202
--- /dev/null
+++ b/clang/test/Sema/attr-counted-by-weird-type-positions-late-parsed.c
@@ -0,0 +1,456 @@
+// RUN: %clang_cc1 -fexperimental-late-parse-attributes -fsyntax-only -verify 
%s
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+// ============================================================================
+// SIMPLE POINTER: int *buf
+// ============================================================================
+
+// Position: after *, before identifier
+// Applies to `int *`.
+struct ptr_after_star {
+  int *__counted_by(count) buf;
+  int count;
+};
+
+// Position: before type specifier
+// Applies to the top-level type.
+struct ptr_before_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) int *buf;
+  int count;
+};
+
+// Position: after type, before *
+// Applies to `int`.
+struct ptr_after_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) *buf;
+  int count;
+};
+
+// Position: after identifier
+// Applies to the top-level type.
+struct ptr_after_ident {
+  int *buf __counted_by(count);
+  int count;
+};
+
+// ============================================================================
+// TYPEDEF POINTER: ptr_to_int_t buf
+// ============================================================================
+
+typedef int * ptr_to_int_t;
+
+// Position: after typedef name, before identifier
+// Applies to `ptr_to_int_t`.
+struct typedef_after_type {
+  ptr_to_int_t __counted_by(count) buf;
+  int count;
+};
+
+// Position: before typedef name
+// Applies to the top-level type.
+struct typedef_before_type {
+  __counted_by(count) ptr_to_int_t buf;
+  int count;
+};
+
+// Position: after identifier
+// Applies to the top-level type.
+struct typedef_after_ident {
+  ptr_to_int_t buf __counted_by(count);
+  int count;
+};
+
+// ============================================================================
+// POINTER TO ARRAY: int (*buf)[4]
+// ============================================================================
+
+// Position: after type, before (*...)
+// Applies to `int`.
+struct ptr_to_arr_after_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* buf)[4];
+  int count;
+};
+
+// Position: before type
+// Applies to the top-level type.
+struct ptr_to_arr_before_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) int (* buf)[4];
+  int count;
+};
+
+// Position: after *, before identifier (inside parens)
+// Applies to `int (*)[4]`.
+struct ptr_to_arr_after_star {
+  int (* __counted_by(count) buf)[4];
+  int count;
+};
+
+// Position: after identifier, before ) (inside parens)
+// Invalid position - causes parse error
+struct ptr_to_arr_after_ident {
+  int (*buf __counted_by(count))[4]; // Invalid position
+  // expected-error@-1{{expected ')'}}
+  // expected-note@-2{{to match this '('}}
+  int count;
+};
+
+// Position: after [4]
+// Applies to the top-level type.
+struct ptr_to_arr_after_brackets {
+  int (* buf)[4] __counted_by(count);
+  int count;
+};
+
+// Position: after (, before *
+struct ptr_to_arr_after_lparen {
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  int (__counted_by(count) *buf)[4];
+  int count;
+};
+
+// Position: inside [4]
+struct ptr_to_arr_inside_brackets {
+  int (* buf)[4 __counted_by(count)]; // Invalid syntax
+  // expected-error@-1{{expected ']'}}
+  // expected-note@-2{{to match this '['}}
+  int count;
+};
+
+// Position: before [4]
+struct ptr_to_arr_before_brackets {
+  // expected-error@+1{{expected ';' at end of declaration list}}
+  int (* buf) __counted_by(count) [4]; // Invalid syntax
+  int count;
+};
+
+// Position: double parens, after ((, before *
+struct ptr_to_arr_double_paren1 {
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  int ((__counted_by(count) * buf))[4];
+  int count;
+};
+
+// Position: double parens, after *, before identifier
+struct ptr_to_arr_double_paren2 {
+  int ((* __counted_by(count) buf))[4];
+  int count;
+};
+
+// ============================================================================
+// POINTER TO ARRAY WITH QUALIFIERS
+// ============================================================================
+
+// const pointer
+struct ptr_to_arr_const_ptr1 {
+  int (* const __counted_by(count) buf)[4];
+  int count;
+};
+
+struct ptr_to_arr_const_ptr2 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* const buf)[4];
+  int count;
+};
+
+// pointer to const
+struct ptr_to_arr_ptr_to_const {
+  const int (* __counted_by(count) buf)[4];
+  int count;
+};
+
+struct ptr_to_arr_ptr_to_const2 {
+  int const (* __counted_by(count) buf)[4];
+  int count;
+};
+
+// restrict pointer
+struct ptr_to_arr_restrict1 {
+  int (* __restrict __counted_by(count) buf)[4];
+  int count;
+};
+
+struct ptr_to_arr_restrict2 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* __restrict buf)[4];
+  int count;
+};
+
+// ============================================================================
+// POINTER TO MULTI-DIMENSIONAL ARRAY: int (*buf)[4][8]
+// ============================================================================
+
+struct ptr_to_multidim_arr_after_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* buf)[4][8];
+  int count;
+};
+
+struct ptr_to_multidim_arr_after_star {
+  int (* __counted_by(count) buf)[4][8];
+  int count;
+};
+
+struct ptr_to_multidim_arr_middle {
+  // expected-error@+1{{expected ';' at end of declaration list}}
+  int (* buf)[4] __counted_by(count) [8]; // Invalid position
+  int count;
+};
+
+struct ptr_to_multidim_arr_after_all {
+  int (* buf)[4][8] __counted_by(count);
+  // This doesn't trigger an error - the attribute applies to the pointer
+  int count;
+};
+
+// ============================================================================
+// ARRAY OF POINTERS TO ARRAY: int (*buf[10])[4]
+// ============================================================================
+
+struct arr_of_ptr_to_arr_after_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* buf[10])[4];
+  int count;
+};
+
+struct arr_of_ptr_to_arr_after_star {
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  int (* __counted_by(count) buf[10])[4];
+  int count;
+};
+
+struct arr_of_ptr_to_arr_middle {
+  // expected-error@+2{{'counted_by' on arrays only applies to C99 flexible 
array members}}
+  // expected-error@+1{{expected ';' at end of declaration list}}
+  int (* buf[10]) __counted_by(count) [4]; // Invalid position
+  int count;
+};
+
+struct arr_of_ptr_to_arr_inside_first_brackets {
+  int (* buf __counted_by(count) [10])[4];
+  // expected-error@-1{{expected ')'}}
+  // expected-note@-2{{to match this '('}}
+  int count;
+};
+
+// ============================================================================
+// TYPEDEF ARRAY: arr4_t *buf where arr4_t is int[4]
+// ============================================================================
+
+typedef int arr4_t[4];
+
+struct typedef_arr_before_type {
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  __counted_by(count) arr4_t * buf;
+  int count;
+};
+
+struct typedef_arr_after_type {
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  arr4_t __counted_by(count) * buf;
+  int count;
+};
+
+struct typedef_arr_after_star {
+  arr4_t * __counted_by(count) buf;
+  int count;
+};
+
+// ============================================================================
+// FUNCTION POINTER: int (*buf)(void)
+// ============================================================================
+
+// Position: after *, before identifier
+struct fptr_after_star {
+  // expected-error@+1{{'counted_by' cannot be applied to a pointer with 
pointee of unknown size because 'int (void)' is a function type}}
+  int (* __counted_by(count) buf)(void);
+  int count;
+};
+
+// Position: after (, before *
+struct fptr_after_lparen {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int (__counted_by(count) *buf)(void);
+  int count;
+};
+
+// ============================================================================
+// _ATOMIC POINTER VARIATIONS
+// ============================================================================
+
+// _Atomic(int *) - atomic pointer type
+struct atomic_ptr_type {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  _Atomic(int *) __counted_by(count) buf;
+  int count;
+};
+
+// Attribute inside _Atomic (likely invalid)
+struct atomic_ptr_attr_inside {
+  // expected-error@+1{{use of undeclared identifier 'count'}}
+  _Atomic(int *__counted_by(count)) buf;
+  int count;
+};
+
+struct atomic_ptr_attr_inside_no_forward_ref {
+  int count;
+  // FIXME: should not be allowed
+  _Atomic(int *__counted_by(count)) buf;
+};
+
+struct atomic_ptr_attr_after {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) _Atomic(int *) buf;
+  int count;
+};
+
+struct atomic_ptr_attr_after_no_forward_ref {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) _Atomic(int *) buf;
+};
+
+// _Atomic int * - could be atomic int or atomic pointer
+struct atomic_ambiguous {
+  _Atomic int * __counted_by(count) buf;
+  int count;
+};
+
+// int *_Atomic - atomic pointer (unambiguous)
+struct atomic_ptr_unambiguous1 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int *_Atomic __counted_by(count) buf;
+  int count;
+};
+
+// __counted_by before _Atomic
+struct atomic_ptr_attr_before_atomic1 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int *__counted_by(count) _Atomic buf;
+  int count;
+};
+
+// __counted_by before * _Atomic
+struct atomic_ptr_attr_before_atomic2 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) * _Atomic buf;
+  int count;
+};
+
+// _Atomic before type
+struct atomic_ptr_atomic_first1 {
+  _Atomic int *__counted_by(count) buf;
+  int count;
+};
+
+// _Atomic before type, attribute after *
+struct atomic_ptr_atomic_first2 {
+  _Atomic int * __counted_by(count) buf;
+  int count;
+};
+
+// __counted_by at the end
+struct atomic_ptr_attr_at_end1 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int *_Atomic buf __counted_by(count);
+  int count;
+};
+
+// __counted_by at the end with space
+struct atomic_ptr_attr_at_end2 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic buf __counted_by(count);
+  int count;
+};
+
+// ============================================================================
+// _ATOMIC POINTER TO ARRAY
+// ============================================================================
+
+struct atomic_ptr_to_arr1 {
+  _Atomic int (* __counted_by(count) buf)[4];
+  int count;
+};
+
+struct atomic_ptr_to_arr2 {
+  // expected-error@+3{{expected a type}}
+  // expected-error@+2{{use of undeclared identifier 'count'}}
+  // expected-error@+1{{expected member name or ';' after declaration 
specifiers}}
+  int _Atomic (* __counted_by(count) buf)[4];
+  int count;
+};
+
+struct atomic_ptr_to_arr3 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int (* _Atomic __counted_by(count) buf)[4];
+  int count;
+};
+
+// ============================================================================
+// ATOMIC WITH CONST/VOLATILE/RESTRICT QUALIFIERS
+// ============================================================================
+
+// const _Atomic pointer
+struct atomic_const_ptr1 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * const _Atomic __counted_by(count) buf;
+  int count;
+};
+
+struct atomic_const_ptr2 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic const __counted_by(count) buf;
+  int count;
+};
+
+struct atomic_const_ptr3 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  const int * _Atomic __counted_by(count) buf;
+  int count;
+};
+
+// volatile _Atomic pointer
+struct atomic_volatile_ptr1 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * volatile _Atomic __counted_by(count) buf;
+  int count;
+};
+
+struct atomic_volatile_ptr2 {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic volatile __counted_by(count) buf;
+  int count;
+};
+
+// restrict _Atomic pointer
+struct atomic_restrict_ptr1 {
+  // expected-error@+2{{restrict requires a pointer or reference ('_Atomic(int 
*)' is invalid)}}
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * __restrict _Atomic __counted_by(count) buf;
+  int count;
+};
+
+struct atomic_restrict_ptr2 {
+  // expected-error@+2{{restrict requires a pointer or reference ('_Atomic(int 
*)' is invalid)}}
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic __restrict __counted_by(count) buf;
+  int count;
+};
+
+// Combined qualifiers
+struct atomic_const_volatile_ptr {
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * const volatile _Atomic __counted_by(count) buf;
+  int count;
+};
+
+struct atomic_all_qualifiers {
+  // expected-error@+2{{restrict requires a pointer or reference ('_Atomic(int 
*)' is invalid)}}
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * const volatile __restrict _Atomic __counted_by(count) buf;
+  int count;
+};
diff --git a/clang/test/Sema/attr-counted-by-weird-type-positions.c 
b/clang/test/Sema/attr-counted-by-weird-type-positions.c
new file mode 100644
index 0000000000000..2668ab1e18346
--- /dev/null
+++ b/clang/test/Sema/attr-counted-by-weird-type-positions.c
@@ -0,0 +1,454 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+#define __counted_by(f)  __attribute__((counted_by(f)))
+
+// ============================================================================
+// SIMPLE POINTER: int *buf
+// ============================================================================
+
+// Position: after *, before identifier
+// Applies to `int *`.
+struct ptr_after_star {
+  int count;
+  int *__counted_by(count) buf;
+};
+
+// Position: before type specifier
+// Applies to the top-level type.
+struct ptr_before_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) int *buf;
+};
+
+// Position: after type, before *
+// Applies to `int`.
+struct ptr_after_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) *buf;
+};
+
+// Position: after identifier
+// Applies to the top-level type.
+struct ptr_after_ident {
+  int count;
+  int *buf __counted_by(count);
+};
+
+// ============================================================================
+// TYPEDEF POINTER: ptr_to_int_t buf
+// ============================================================================
+
+typedef int * ptr_to_int_t;
+
+// Position: after typedef name, before identifier
+// Applies to `ptr_to_int_t`.
+struct typedef_after_type {
+  int count;
+  ptr_to_int_t __counted_by(count) buf;
+};
+
+// Position: before typedef name
+// Applies to the top-level type.
+struct typedef_before_type {
+  int count;
+  __counted_by(count) ptr_to_int_t buf;
+};
+
+// Position: after identifier
+// Applies to the top-level type.
+struct typedef_after_ident {
+  int count;
+  ptr_to_int_t buf __counted_by(count);
+};
+
+// ============================================================================
+// POINTER TO ARRAY: int (*buf)[4]
+// ============================================================================
+
+// Position: after type, before (*...)
+// Applies to `int`.
+struct ptr_to_arr_after_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* buf)[4];
+};
+
+// Position: before type
+// Applies to the top-level type.
+struct ptr_to_arr_before_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) int (* buf)[4];
+};
+
+// Position: after *, before identifier (inside parens)
+// Applies to `int (*)[4]`.
+struct ptr_to_arr_after_star {
+  int count;
+  int (* __counted_by(count) buf)[4];
+};
+
+// Position: after identifier, before ) (inside parens)
+// Invalid position - causes parse error
+struct ptr_to_arr_after_ident {
+  int count;
+  int (*buf __counted_by(count))[4]; // Invalid position
+  // expected-error@-1{{expected ')'}}
+  // expected-note@-2{{to match this '('}}
+};
+
+// Position: after [4]
+// Applies to the top-level type.
+struct ptr_to_arr_after_brackets {
+  int count;
+  int (* buf)[4] __counted_by(count);
+};
+
+// Position: after (, before *
+struct ptr_to_arr_after_lparen {
+  int count;
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  int (__counted_by(count) *buf)[4];
+};
+
+// Position: inside [4]
+struct ptr_to_arr_inside_brackets {
+  int count;
+  int (* buf)[4 __counted_by(count)]; // Invalid syntax
+  // expected-error@-1{{expected ']'}}
+  // expected-note@-2{{to match this '['}}
+};
+
+// Position: before [4]
+struct ptr_to_arr_before_brackets {
+  int count;
+  // expected-error@+1{{expected ';' at end of declaration list}}
+  int (* buf) __counted_by(count) [4]; // Invalid syntax
+};
+
+// Position: double parens, after ((, before *
+struct ptr_to_arr_double_paren1 {
+  int count;
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  int ((__counted_by(count) * buf))[4];
+};
+
+// Position: double parens, after *, before identifier
+struct ptr_to_arr_double_paren2 {
+  int count;
+  int ((* __counted_by(count) buf))[4];
+};
+
+// ============================================================================
+// POINTER TO ARRAY WITH QUALIFIERS
+// ============================================================================
+
+// const pointer
+struct ptr_to_arr_const_ptr1 {
+  int count;
+  int (* const __counted_by(count) buf)[4];
+};
+
+struct ptr_to_arr_const_ptr2 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* const buf)[4];
+};
+
+// pointer to const
+struct ptr_to_arr_ptr_to_const {
+  int count;
+  const int (* __counted_by(count) buf)[4];
+};
+
+struct ptr_to_arr_ptr_to_const2 {
+  int count;
+  int const (* __counted_by(count) buf)[4];
+};
+
+// restrict pointer
+struct ptr_to_arr_restrict1 {
+  int count;
+  int (* __restrict __counted_by(count) buf)[4];
+};
+
+struct ptr_to_arr_restrict2 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* __restrict buf)[4];
+};
+
+// ============================================================================
+// POINTER TO MULTI-DIMENSIONAL ARRAY: int (*buf)[4][8]
+// ============================================================================
+
+struct ptr_to_multidim_arr_after_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* buf)[4][8];
+};
+
+struct ptr_to_multidim_arr_after_star {
+  int count;
+  int (* __counted_by(count) buf)[4][8];
+};
+
+struct ptr_to_multidim_arr_middle {
+  int count;
+  // expected-error@+1{{expected ';' at end of declaration list}}
+  int (* buf)[4] __counted_by(count) [8]; // Invalid position
+};
+
+struct ptr_to_multidim_arr_after_all {
+  int count;
+  int (* buf)[4][8] __counted_by(count);
+  // This doesn't trigger an error - the attribute applies to the pointer
+};
+
+// ============================================================================
+// ARRAY OF POINTERS TO ARRAY: int (*buf[10])[4]
+// ============================================================================
+
+struct arr_of_ptr_to_arr_after_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) (* buf[10])[4];
+};
+
+struct arr_of_ptr_to_arr_after_star {
+  int count;
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  int (* __counted_by(count) buf[10])[4];
+};
+
+struct arr_of_ptr_to_arr_middle {
+  int count;
+  // expected-error@+2{{'counted_by' on arrays only applies to C99 flexible 
array members}}
+  // expected-error@+1{{expected ';' at end of declaration list}}
+  int (* buf[10]) __counted_by(count) [4]; // Invalid position
+};
+
+struct arr_of_ptr_to_arr_inside_first_brackets {
+  int count;
+  int (* buf __counted_by(count) [10])[4];
+  // expected-error@-1{{expected ')'}}
+  // expected-note@-2{{to match this '('}}
+};
+
+// ============================================================================
+// TYPEDEF ARRAY: arr4_t *buf where arr4_t is int[4]
+// ============================================================================
+
+typedef int arr4_t[4];
+
+struct typedef_arr_before_type {
+  int count;
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  __counted_by(count) arr4_t * buf;
+};
+
+struct typedef_arr_after_type {
+  int count;
+  // expected-error@+1{{'counted_by' attribute on nested pointer type is not 
allowed}}
+  arr4_t __counted_by(count) * buf;
+};
+
+struct typedef_arr_after_star {
+  int count;
+  arr4_t * __counted_by(count) buf;
+};
+
+// ============================================================================
+// FUNCTION POINTER: int (*buf)(void)
+// ============================================================================
+
+// Position: after *, before identifier
+struct fptr_after_star {
+  int count;
+  // expected-error@+1{{'counted_by' cannot be applied to a pointer with 
pointee of unknown size because 'int (void)' is a function type}}
+  int (* __counted_by(count) buf)(void);
+};
+
+// Position: after (, before *
+struct fptr_after_lparen {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int (__counted_by(count) *buf)(void);
+};
+
+// ============================================================================
+// _ATOMIC POINTER VARIATIONS
+// ============================================================================
+
+// _Atomic(int *) - atomic pointer type
+struct atomic_ptr_type {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  _Atomic(int *) __counted_by(count) buf;
+};
+
+// Attribute inside _Atomic (likely invalid)
+struct atomic_ptr_attr_inside {
+  int count;
+  _Atomic(int *__counted_by(count)) buf;
+};
+
+struct atomic_ptr_attr_inside_no_forward_ref {
+  int count;
+  // FIXME: should not be allowed
+  _Atomic(int *__counted_by(count)) buf;
+};
+
+struct atomic_ptr_attr_after {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) _Atomic(int *) buf;
+};
+
+struct atomic_ptr_attr_after_no_forward_ref {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  __counted_by(count) _Atomic(int *) buf;
+};
+
+// _Atomic int * - could be atomic int or atomic pointer
+struct atomic_ambiguous {
+  int count;
+  _Atomic int * __counted_by(count) buf;
+};
+
+// int *_Atomic - atomic pointer (unambiguous)
+struct atomic_ptr_unambiguous1 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int *_Atomic __counted_by(count) buf;
+};
+
+// __counted_by before _Atomic
+struct atomic_ptr_attr_before_atomic1 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int *__counted_by(count) _Atomic buf;
+};
+
+// __counted_by before * _Atomic
+struct atomic_ptr_attr_before_atomic2 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int __counted_by(count) * _Atomic buf;
+};
+
+// _Atomic before type
+struct atomic_ptr_atomic_first1 {
+  int count;
+  _Atomic int *__counted_by(count) buf;
+};
+
+// _Atomic before type, attribute after *
+struct atomic_ptr_atomic_first2 {
+  int count;
+  _Atomic int * __counted_by(count) buf;
+};
+
+// __counted_by at the end
+struct atomic_ptr_attr_at_end1 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int *_Atomic buf __counted_by(count);
+};
+
+// __counted_by at the end with space
+struct atomic_ptr_attr_at_end2 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic buf __counted_by(count);
+};
+
+// ============================================================================
+// _ATOMIC POINTER TO ARRAY
+// ============================================================================
+
+struct atomic_ptr_to_arr1 {
+  int count;
+  _Atomic int (* __counted_by(count) buf)[4];
+};
+
+struct atomic_ptr_to_arr2 {
+  int count;
+  // expected-error@+2{{expected a type}}
+  // expected-error@+1{{expected member name or ';' after declaration 
specifiers}}
+  int _Atomic (* __counted_by(count) buf)[4];
+};
+
+struct atomic_ptr_to_arr3 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int (* _Atomic __counted_by(count) buf)[4];
+};
+
+// ============================================================================
+// ATOMIC WITH CONST/VOLATILE/RESTRICT QUALIFIERS
+// ============================================================================
+
+// const _Atomic pointer
+struct atomic_const_ptr1 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * const _Atomic __counted_by(count) buf;
+};
+
+struct atomic_const_ptr2 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic const __counted_by(count) buf;
+};
+
+struct atomic_const_ptr3 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  const int * _Atomic __counted_by(count) buf;
+};
+
+// volatile _Atomic pointer
+struct atomic_volatile_ptr1 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * volatile _Atomic __counted_by(count) buf;
+};
+
+struct atomic_volatile_ptr2 {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic volatile __counted_by(count) buf;
+};
+
+// restrict _Atomic pointer
+struct atomic_restrict_ptr1 {
+  int count;
+  // expected-error@+2{{restrict requires a pointer or reference ('_Atomic(int 
*)' is invalid)}}
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * __restrict _Atomic __counted_by(count) buf;
+};
+
+struct atomic_restrict_ptr2 {
+  int count;
+  // expected-error@+2{{restrict requires a pointer or reference ('_Atomic(int 
*)' is invalid)}}
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * _Atomic __restrict __counted_by(count) buf;
+};
+
+// Combined qualifiers
+struct atomic_const_volatile_ptr {
+  int count;
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * const volatile _Atomic __counted_by(count) buf;
+};
+
+struct atomic_all_qualifiers {
+  int count;
+  // expected-error@+2{{restrict requires a pointer or reference ('_Atomic(int 
*)' is invalid)}}
+  // expected-error@+1{{'counted_by' only applies to pointers or C99 flexible 
array members}}
+  int * const volatile __restrict _Atomic __counted_by(count) buf;
+};

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to