Skip to content

Commit 9ec3203

Browse files
committed
* Tweak new diagnostic message
* Rename `attr-counted-by.c` -> `attr-counted-by-vla.c` * Disallow `__counted_by` on VLA if element type is a struct with a VLA (addresses @hnrklssn 's feedback)
1 parent 1f4d924 commit 9ec3203

7 files changed

+168
-40
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6537,14 +6537,16 @@ def err_counted_by_attr_refer_to_union : Error<
65376537
def note_flexible_array_counted_by_attr_field : Note<
65386538
"field %0 declared here">;
65396539
def err_counted_by_attr_pointee_unknown_size : Error<
6540-
"'counted_by' cannot be applied a pointer with pointee with unknown size "
6541-
"because %0 is %select{"
6540+
"'counted_by' cannot be applied to %select{"
6541+
"a pointer with pointee|" // pointer
6542+
"an array with element}0" // array
6543+
" of unknown size because %1 is %select{"
65426544
"an incomplete type|" // CountedByInvalidPointeeTypeKind::INCOMPLETE
65436545
"a sizeless type|" // CountedByInvalidPointeeTypeKind::SIZELESS
65446546
"a function type|" // CountedByInvalidPointeeTypeKind::FUNCTION
65456547
// CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER
65466548
"a struct type with a flexible array member"
6547-
"}1">;
6549+
"}2">;
65486550

65496551
let CategoryName = "ARC Semantic Issue" in {
65506552

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8626,26 +8626,37 @@ static bool CheckCountedByAttrOnField(
86268626
return true;
86278627
}
86288628

8629+
CountedByInvalidPointeeTypeKind InvalidTypeKind =
8630+
CountedByInvalidPointeeTypeKind::VALID;
8631+
QualType PointeeTy;
8632+
int SelectPtrOrArr = 0;
86298633
if (FieldTy->isPointerType()) {
8630-
CountedByInvalidPointeeTypeKind InvalidTypeKind =
8631-
CountedByInvalidPointeeTypeKind::VALID;
8632-
const auto PointeeTy = FieldTy->getPointeeType();
8633-
if (PointeeTy->isIncompleteType()) {
8634-
InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
8635-
} else if (PointeeTy->isSizelessType()) {
8636-
InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
8637-
} else if (PointeeTy->isFunctionType()) {
8638-
InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION;
8639-
} else if (PointeeTy->isStructureTypeWithFlexibleArrayMember()) {
8640-
InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER;
8641-
}
8642-
8643-
if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) {
8644-
S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_pointee_unknown_size)
8645-
<< FieldTy->getPointeeType() << (int)InvalidTypeKind
8646-
<< FD->getSourceRange();
8647-
return true;
8648-
}
8634+
PointeeTy = FieldTy->getPointeeType();
8635+
SelectPtrOrArr = 0;
8636+
} else {
8637+
assert(FieldTy->isArrayType());
8638+
const ArrayType *AT = S.getASTContext().getAsArrayType(FieldTy);
8639+
PointeeTy = AT->getElementType();
8640+
SelectPtrOrArr = 1;
8641+
}
8642+
// Note: The `Decl::isFlexibleArrayMemberLike` check earlier on means
8643+
// only `PointeeTy->isStructureTypeWithFlexibleArrayMember()` is reachable
8644+
// when `FieldTy->isArrayType()`.
8645+
if (PointeeTy->isIncompleteType()) {
8646+
InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
8647+
} else if (PointeeTy->isSizelessType()) {
8648+
InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
8649+
} else if (PointeeTy->isFunctionType()) {
8650+
InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION;
8651+
} else if (PointeeTy->isStructureTypeWithFlexibleArrayMember()) {
8652+
InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER;
8653+
}
8654+
8655+
if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) {
8656+
S.Diag(FD->getBeginLoc(), diag::err_counted_by_attr_pointee_unknown_size)
8657+
<< SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind
8658+
<< FD->getSourceRange();
8659+
return true;
86498660
}
86508661

86518662
// Check the expression

clang/test/Sema/attr-counted-by-late-parsed-struct-ptrs.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,24 @@ struct on_member_pointer_complete_ty {
1717
};
1818

1919
struct on_member_pointer_incomplete_ty {
20-
struct size_unknown * buf __counted_by(count); // expected-error{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct size_unknown' is an incomplete type}}
20+
struct size_unknown * buf __counted_by(count); // expected-error{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct size_unknown' is an incomplete type}}
2121
int count;
2222
};
2323

24+
struct on_member_pointer_const_incomplete_ty {
25+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'const struct size_unknown' is an incomplete type}}
26+
const struct size_unknown * buf __counted_by(count);
27+
int count;
28+
};
29+
30+
2431
struct on_member_pointer_void_ty {
25-
void* buf __counted_by(count); // expected-error{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'void' is an incomplete type}}
32+
void* buf __counted_by(count); // expected-error{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void' is an incomplete type}}
2633
int count;
2734
};
2835

2936
struct on_member_pointer_fn_ty {
30-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'void (void)' is a function type}}
37+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
3138
void (*fn_ptr)(void) __counted_by(count);
3239
int count;
3340
};
@@ -38,7 +45,7 @@ struct has_unannotated_vla {
3845
};
3946

4047
struct on_member_pointer_struct_with_vla {
41-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
48+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
4249
struct has_unannotated_vla* objects __counted_by(count);
4350
int count;
4451
};
@@ -52,7 +59,7 @@ struct has_annotated_vla {
5259
// require an O(N) walk of `objects` to take into account the length of the VLA
5360
// in each struct instance.
5461
struct on_member_pointer_struct_with_annotated_vla {
55-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
62+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
5663
struct has_annotated_vla* objects __counted_by(count);
5764
int count;
5865
};
@@ -94,6 +101,13 @@ struct on_member_pointer_incomplete_ty_ty_pos {
94101
int count;
95102
};
96103

104+
struct on_member_pointer_const_incomplete_ty_ty_pos {
105+
// TODO: Allow this
106+
// expected-error@+1{{use of undeclared identifier 'count'}}
107+
const struct size_unknown * __counted_by(count) buf;
108+
int count;
109+
};
110+
97111
struct on_member_pointer_void_ty_ty_pos {
98112
// TODO: This should fail because the attribute is
99113
// on a pointer with the pointee being an incomplete type.

clang/test/Sema/attr-counted-by-struct-ptrs-sizeless-types.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
struct on_sizeless_pointee_ty {
77
int count;
8-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because '__SVInt8_t' is a sizeless type}}
8+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because '__SVInt8_t' is a sizeless type}}
99
__SVInt8_t* member __counted_by(count);
1010
};
1111

clang/test/Sema/attr-counted-by-struct-ptrs.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,25 @@ struct on_member_pointer_complete_ty {
1818

1919
struct on_member_pointer_incomplete_ty {
2020
int count;
21-
struct size_unknown * buf __counted_by(count); // expected-error{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct size_unknown' is an incomplete type}}
21+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct size_unknown' is an incomplete type}}
22+
struct size_unknown * buf __counted_by(count);
23+
};
24+
25+
struct on_member_pointer_const_incomplete_ty {
26+
int count;
27+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'const struct size_unknown' is an incomplete type}}
28+
const struct size_unknown * buf __counted_by(count);
2229
};
2330

2431
struct on_member_pointer_void_ty {
2532
int count;
26-
void* buf __counted_by(count); // expected-error{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'void' is an incomplete type}}
33+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void' is an incomplete type}}
34+
void* buf __counted_by(count);
2735
};
2836

2937
struct on_member_pointer_fn_ty {
3038
int count;
31-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'void (void)' is a function type}}
39+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
3240
void (*fn_ptr)(void) __counted_by(count);
3341
};
3442

@@ -39,7 +47,7 @@ struct has_unannotated_vla {
3947

4048
struct on_member_pointer_struct_with_vla {
4149
int count;
42-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
50+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
4351
struct has_unannotated_vla* objects __counted_by(count);
4452
};
4553

@@ -53,7 +61,7 @@ struct has_annotated_vla {
5361
// in each struct instance.
5462
struct on_member_pointer_struct_with_annotated_vla {
5563
int count;
56-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
64+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
5765
struct has_annotated_vla* objects __counted_by(count);
5866
};
5967

@@ -79,22 +87,30 @@ struct on_pointer_anon_count {
7987

8088
struct on_member_pointer_complete_ty_ty_pos {
8189
int count;
82-
struct size_known *__counted_by(count) buf ;
90+
struct size_known *__counted_by(count) buf;
8391
};
8492

8593
struct on_member_pointer_incomplete_ty_ty_pos {
8694
int count;
87-
struct size_unknown * __counted_by(count) buf; // expected-error{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct size_unknown' is an incomplete type}}
95+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct size_unknown' is an incomplete type}}
96+
struct size_unknown * __counted_by(count) buf;
97+
};
98+
99+
struct on_member_pointer_const_incomplete_ty_ty_pos {
100+
int count;
101+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'const struct size_unknown' is an incomplete type}}
102+
const struct size_unknown * __counted_by(count) buf;
88103
};
89104

90105
struct on_member_pointer_void_ty_ty_pos {
91106
int count;
92-
void *__counted_by(count) buf; // expected-error{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'void' is an incomplete type}}
107+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void' is an incomplete type}}
108+
void *__counted_by(count) buf;
93109
};
94110

95111
struct on_member_pointer_fn_ty_ty_pos {
96112
int count;
97-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'void (void)' is a function type}}
113+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'void (void)' is a function type}}
98114
void (* __counted_by(count) fn_ptr)(void);
99115
};
100116

@@ -113,7 +129,7 @@ struct on_member_pointer_fn_ptr_ty_ty_pos_inner {
113129

114130
struct on_member_pointer_struct_with_vla_ty_pos {
115131
int count;
116-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
132+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_unannotated_vla' is a struct type with a flexible array member}}
117133
struct has_unannotated_vla *__counted_by(count) objects;
118134
};
119135

@@ -122,7 +138,7 @@ struct on_member_pointer_struct_with_vla_ty_pos {
122138
// in each struct instance.
123139
struct on_member_pointer_struct_with_annotated_vla_ty_pos {
124140
int count;
125-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
141+
// expected-error@+1{{counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct has_annotated_vla' is a struct type with a flexible array member}}
126142
struct has_annotated_vla* __counted_by(count) objects;
127143
};
128144

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// __SVInt8_t is specific to ARM64 so specify that in the target triple
2+
// RUN: %clang_cc1 -triple arm64-apple-darwin -fsyntax-only -verify %s
3+
4+
#define __counted_by(f) __attribute__((counted_by(f)))
5+
6+
struct on_sizeless_elt_ty {
7+
int count;
8+
// expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}}
9+
// expected-error@+1{{array has sizeless element type '__SVInt8_t'}}
10+
__SVInt8_t arr[] __counted_by(count);
11+
};

clang/test/Sema/attr-counted-by.c renamed to clang/test/Sema/attr-counted-by-vla.c

Lines changed: 75 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ struct array_of_ints_count {
9595

9696
struct not_a_fam {
9797
int count;
98-
// expected-error@+1{{'counted_by' cannot be applied a pointer with pointee with unknown size because 'struct bar' is an incomplete type}}
98+
// expected-error@+1{{'counted_by' cannot be applied to a pointer with pointee of unknown size because 'struct bar' is an incomplete type}}
9999
struct bar *non_fam __counted_by(count);
100100
};
101101

@@ -111,3 +111,77 @@ struct annotated_with_anon_struct {
111111
int array[] __counted_by(crount); // expected-error {{use of undeclared identifier 'crount'}}
112112
};
113113
};
114+
115+
//==============================================================================
116+
// __counted_by on a struct VLA with element type that has unknown size
117+
//==============================================================================
118+
119+
struct size_unknown; // expected-note 2{{forward declaration of 'struct size_unknown'}}
120+
struct on_member_arr_incomplete_ty_ty_pos {
121+
int count;
122+
// expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}}
123+
// expected-error@+1{{array has incomplete element type 'struct size_unknown'}}
124+
struct size_unknown buf[] __counted_by(count);
125+
};
126+
127+
struct on_member_arr_incomplete_const_ty_ty_pos {
128+
int count;
129+
// expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}}
130+
// expected-error@+1{{array has incomplete element type 'const struct size_unknown'}}
131+
const struct size_unknown buf[] __counted_by(count);
132+
};
133+
134+
struct on_member_arr_void_ty_ty_pos {
135+
int count;
136+
// expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}}
137+
// expected-error@+1{{array has incomplete element type 'void'}}
138+
void buf[] __counted_by(count);
139+
};
140+
141+
typedef void(fn_ty)(int);
142+
143+
struct on_member_arr_fn_ty {
144+
int count;
145+
// expected-error@+2{{'counted_by' only applies to pointers or C99 flexible array members}}
146+
// expected-error@+1{{'buf' declared as array of functions of type 'fn_ty' (aka 'void (int)')}}
147+
fn_ty buf[] __counted_by(count);
148+
};
149+
150+
151+
152+
// `buffer_of_structs_with_unnannotated_vla`,
153+
// `buffer_of_structs_with_annotated_vla`, and
154+
// `buffer_of_const_structs_with_annotated_vla` are currently prevented because
155+
// computing the size of `Arr` at runtime would require an O(N) walk of `Arr`
156+
// elements to take into account the length of the VLA in each struct instance.
157+
158+
struct has_unannotated_VLA {
159+
int count;
160+
char buffer[];
161+
};
162+
163+
struct has_annotated_VLA {
164+
int count;
165+
char buffer[] __counted_by(count);
166+
};
167+
168+
struct buffer_of_structs_with_unnannotated_vla {
169+
int count;
170+
// expected-error@+1{{'counted_by' cannot be applied to an array with element of unknown size because 'struct has_unannotated_VLA' is a struct type with a flexible array member}}
171+
struct has_unannotated_VLA Arr[] __counted_by(count);
172+
};
173+
174+
175+
struct buffer_of_structs_with_annotated_vla {
176+
int count;
177+
// expected-error@+1{{'counted_by' cannot be applied to an array with element of unknown size because 'struct has_annotated_VLA' is a struct type with a flexible array member}}
178+
struct has_annotated_VLA Arr[] __counted_by(count);
179+
};
180+
181+
struct buffer_of_const_structs_with_annotated_vla {
182+
int count;
183+
// Make sure the `const` qualifier is printed when printing the element type.
184+
// expected-error@+1{{'counted_by' cannot be applied to an array with element of unknown size because 'const struct has_annotated_VLA' is a struct type with a flexible array member}}
185+
const struct has_annotated_VLA Arr[] __counted_by(count);
186+
};
187+

0 commit comments

Comments
 (0)