1//===-- SemaBoundsSafety.cpp - Bounds Safety specific routines-*- C++ -*---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9/// This file declares semantic analysis functions specific to `-fbounds-safety`
10/// (Bounds Safety) and also its attributes when used without `-fbounds-safety`
11/// (e.g. `counted_by`)
12///
13//===----------------------------------------------------------------------===//
14#include "clang/Lex/Lexer.h"
15#include "clang/Sema/Initialization.h"
16#include "clang/Sema/Sema.h"
17
18namespace clang {
19
20static CountAttributedType::BoundsAttrKind getCountAttrKind(bool CountInBytes,
21 bool OrNull) {
22 if (CountInBytes)
23 return OrNull ? CountAttributedType::SizedByOrNull
24 : CountAttributedType::SizedBy;
25 return OrNull ? CountAttributedType::CountedByOrNull
26 : CountAttributedType::CountedBy;
27}
28
29BoundsAttributedType::BoundsAttrKind
30Sema::getBoundsAttrKind(const BoundsAttrFlags &Flags) {
31 // Clang does not yet implement __ended_by (see BoundsSafety.md).
32 assert(!Flags.IsEndedBy && "ended_by is not implemented");
33 return getCountAttrKind(CountInBytes: Flags.CountInBytes, OrNull: Flags.OrNull);
34}
35
36Sema::BoundsAttrFlags Sema::BoundsAttrFlags::get(AttributeCommonInfo::Kind K) {
37 BoundsAttrFlags Flags;
38 switch (K) {
39 case ParsedAttr::AT_SizedBy:
40 Flags.CountInBytes = true;
41 break;
42 case ParsedAttr::AT_SizedByOrNull:
43 Flags.CountInBytes = true;
44 Flags.OrNull = true;
45 break;
46 case ParsedAttr::AT_CountedBy:
47 break;
48 case ParsedAttr::AT_CountedByOrNull:
49 Flags.OrNull = true;
50 break;
51 default:
52 llvm_unreachable("unexpected bounds attribute kind");
53 }
54 return Flags;
55}
56
57static const RecordDecl *GetEnclosingNamedOrTopAnonRecord(const FieldDecl *FD) {
58 const auto *RD = FD->getParent();
59 // An unnamed struct is treated as anonymous struct at this point.
60 // A struct may not be fully processed yet to determine
61 // whether it's anonymous or not. In that case, this function treats it as
62 // an anonymous struct and tries to find a named parent.
63 while (RD && (RD->isAnonymousStructOrUnion() || RD->getName().empty())) {
64 const auto *Parent = dyn_cast<RecordDecl>(Val: RD->getParent());
65 if (!Parent)
66 break;
67 RD = Parent;
68 }
69 return RD;
70}
71
72enum class CountedByInvalidPointeeTypeKind {
73 INCOMPLETE,
74 SIZELESS,
75 FUNCTION,
76 FLEXIBLE_ARRAY_MEMBER,
77 VALID,
78};
79
80/// Check type conflicts under the -fbounds-safety attribute model.
81/// Return std::nullopt if validation should continue with the shared checks.
82static std::optional<bool> checkBoundsAttrTypeConflictsAndMisc(
83 Sema &S, QualType Ty, SourceLocation AttrLoc,
84 const Sema::BoundsAttrFlags &Flags, StringRef AttrSpelling,
85 bool AllowRedecl, Expr *AttrArg) {
86 // The -fbounds-safety model's checks for conflicting attributes, atomic
87 // pointers and array shapes are not upstream yet.
88 return std::nullopt;
89}
90
91bool Sema::ValidateBoundsAttrTypeShape(QualType Ty, SourceLocation AttrLoc,
92 SourceRange AttrRange,
93 BoundsAttrFlags &Flags,
94 StringRef AttrSpelling, bool AllowRedecl,
95 Expr *AttrArg, bool UpdateFlags) {
96 if (getLangOpts().hasBoundsSafetyAttributes())
97 if (std::optional<bool> Result = checkBoundsAttrTypeConflictsAndMisc(
98 S&: *this, Ty, AttrLoc, Flags, AttrSpelling, AllowRedecl, AttrArg))
99 return *Result;
100
101 BoundsAttributedType::BoundsAttrKind Kind = getBoundsAttrKind(Flags);
102
103 // counted_by and sized_by require a pointer or array.
104 if (!Ty->isPointerType() && !Ty->isArrayType()) {
105 Diag(Loc: AttrLoc, DiagID: diag::err_count_attr_not_on_ptr_or_flexible_array_member)
106 << Kind << 0;
107 return false;
108 }
109
110 // Arrays only support counted_by outside the -fbounds-safety attribute model.
111 if (!getLangOpts().hasBoundsSafetyAttributes() && Ty->isArrayType() &&
112 (Flags.CountInBytes || Flags.OrNull)) {
113 Diag(Loc: AttrLoc, DiagID: diag::err_count_attr_not_on_ptr_or_flexible_array_member)
114 << Kind << /*suggest counted_by*/ 1;
115 return false;
116 }
117
118 // Check the pointee or element type.
119 QualType PointeeTy;
120 int SelectPtrOrArr;
121 if (Ty->isPointerType()) {
122 PointeeTy = Ty->getPointeeType();
123 SelectPtrOrArr = 0;
124 } else {
125 const ArrayType *AT = getASTContext().getAsArrayType(T: Ty);
126 PointeeTy = AT->getElementType();
127 SelectPtrOrArr = 1;
128 }
129
130 auto InvalidTypeKind = CountedByInvalidPointeeTypeKind::VALID;
131 bool ShouldWarn = false;
132 if (!Flags.CountInBytes && PointeeTy->isAlwaysIncompleteType()) {
133 // In general using `counted_by` or `counted_by_or_null` on
134 // pointers where the pointee is an incomplete type are problematic. This
135 // is because it isn't possible to compute the pointer's bounds without
136 // knowing the pointee type size. At the same time it is common to forward
137 // declare types in header files.
138 //
139 // E.g.:
140 //
141 // struct Handle;
142 // struct Wrapper {
143 // size_t count;
144 // struct Handle* __counted_by(count) handles;
145 // }
146 //
147 // To allow the above code pattern but still prevent the pointee type from
148 // being incomplete in places where bounds checks are needed the following
149 // scheme is used:
150 //
151 // * When the pointee type might not always be an incomplete type (i.e.
152 // a type that is currently incomplete but might be completed later
153 // on in the translation unit) the attribute is allowed by this method
154 // but later uses of the FieldDecl are checked that the pointee type
155 // is complete see `BoundsSafetyCheckAssignmentToCountAttrPtr`,
156 // `BoundsSafetyCheckInitialization`, and
157 // `BoundsSafetyCheckUseOfCountAttrPtr`
158 //
159 // * When the pointee type is always an incomplete type (e.g.
160 // `void` in strict C mode) the attribute is disallowed by this method
161 // because we know the type can never be completed so there's no reason
162 // to allow it.
163 //
164 // Exception: void has an implicit size of 1 byte for pointer arithmetic
165 // (following GNU convention). Therefore, counted_by on void* is allowed
166 // and behaves equivalently to sized_by (treating the count as bytes).
167 if (PointeeTy->isVoidType() && !getLangOpts().hasBoundsSafetyAttributes()) {
168 // Emit a warning that this is a GNU extension.
169 Diag(Loc: AttrLoc, DiagID: diag::ext_gnu_counted_by_void_ptr) << Kind;
170 Diag(Loc: AttrLoc, DiagID: diag::note_gnu_counted_by_void_ptr_use_sized_by) << Kind;
171 assert(!Ty->isArrayType() && "sized_by is not allowed on arrays");
172 if (UpdateFlags)
173 Flags.CountInBytes = true;
174 return true;
175 }
176 InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
177 } else if (PointeeTy->isSizelessType()) {
178 InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
179 } else if (PointeeTy->isFunctionType()) {
180 InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION;
181 } else if (!Flags.CountInBytes &&
182 PointeeTy->isStructureTypeWithFlexibleArrayMember()) {
183 if (Ty->isArrayType()) {
184 // This is a workaround for the Linux kernel that has already adopted
185 // `counted_by` on a FAM where the pointee is a struct with a FAM. This
186 // should be an error because computing the bounds of the array cannot
187 // be done correctly without manually traversing every struct object in
188 // the array at runtime. To allow the code to be built this error is
189 // downgraded to a warning.
190 ShouldWarn = true;
191 }
192 InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER;
193 }
194
195 if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) {
196 unsigned DiagID = ShouldWarn
197 ? diag::warn_counted_by_attr_elt_type_unknown_size
198 : diag::err_counted_by_attr_pointee_unknown_size;
199 Diag(Loc: AttrLoc, DiagID) << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind
200 << (ShouldWarn ? 1 : 0) << Kind << AttrRange;
201 if (ShouldWarn)
202 return true;
203 if (getLangOpts().hasBoundsSafetyAttributes() && !Ty->isArrayType()) {
204 // Under BoundsSafety, recover by switching to byte count so that
205 // type construction can proceed and emit follow-up diagnostics.
206 // We don't do this for arrays because `__sized_by` is not allowed.
207 Flags.CountInBytes = true;
208 return true;
209 }
210 return false;
211 }
212
213 return true;
214}
215
216bool Sema::ValidateBoundsAttrTypeForTypePosition(
217 QualType Ty, AttributeCommonInfo::Kind AttrKind, SourceLocation AttrLoc,
218 SourceRange AttrRange, unsigned PointerNestLevel, BoundsAttrFlags &Flags) {
219 Flags = BoundsAttrFlags::get(K: AttrKind);
220
221 if (!ValidateBoundsAttrTypeShape(Ty, AttrLoc, AttrRange, Flags,
222 /*AttrSpelling=*/{}, /*AllowRedecl=*/false,
223 /*AttrArg=*/nullptr, /*UpdateFlags=*/false))
224 return false;
225
226 // Currently, only attributes at the outermost level of the declared type
227 // are supported.
228 //
229 // FIXME: Support indirect parameters such as:
230 // void f(int *__counted_by(*len) *buf, int *len);
231 // See https://github.com/llvm/llvm-project/issues/166411.
232 if (PointerNestLevel > 0) {
233 Diag(Loc: AttrLoc, DiagID: diag::err_counted_by_on_nested_pointer)
234 << getBoundsAttrKind(Flags);
235 return false;
236 }
237
238 return true;
239}
240
241bool Sema::CheckCountedByAttrOnField(FieldDecl *FD, Expr *E, bool CountInBytes,
242 bool OrNull) {
243 // Check the context the attribute is used in
244
245 unsigned Kind = getCountAttrKind(CountInBytes, OrNull);
246
247 if (FD->getParent()->isUnion()) {
248 Diag(Loc: FD->getBeginLoc(), DiagID: diag::err_count_attr_in_union)
249 << Kind << FD->getSourceRange();
250 return true;
251 }
252
253 const auto FieldTy = FD->getType();
254 if (FieldTy->isArrayType() && (CountInBytes || OrNull)) {
255 Diag(Loc: FD->getBeginLoc(),
256 DiagID: diag::err_count_attr_not_on_ptr_or_flexible_array_member)
257 << Kind << FD->getLocation() << /* suggest counted_by */ 1;
258 return true;
259 }
260 if (!FieldTy->isArrayType() && !FieldTy->isPointerType()) {
261 Diag(Loc: FD->getBeginLoc(),
262 DiagID: diag::err_count_attr_not_on_ptr_or_flexible_array_member)
263 << Kind << FD->getLocation() << /* do not suggest counted_by */ 0;
264 return true;
265 }
266
267 LangOptions::StrictFlexArraysLevelKind StrictFlexArraysLevel =
268 LangOptions::StrictFlexArraysLevelKind::IncompleteOnly;
269 if (FieldTy->isArrayType() &&
270 !Decl::isFlexibleArrayMemberLike(Context: getASTContext(), D: FD, Ty: FieldTy,
271 StrictFlexArraysLevel, IgnoreTemplateOrMacroSubstitution: true)) {
272 Diag(Loc: FD->getBeginLoc(),
273 DiagID: diag::err_counted_by_attr_on_array_not_flexible_array_member)
274 << Kind << FD->getLocation();
275 return true;
276 }
277
278 CountedByInvalidPointeeTypeKind InvalidTypeKind =
279 CountedByInvalidPointeeTypeKind::VALID;
280 QualType PointeeTy;
281 int SelectPtrOrArr = 0;
282 if (FieldTy->isPointerType()) {
283 PointeeTy = FieldTy->getPointeeType();
284 SelectPtrOrArr = 0;
285 } else {
286 assert(FieldTy->isArrayType());
287 const ArrayType *AT = getASTContext().getAsArrayType(T: FieldTy);
288 PointeeTy = AT->getElementType();
289 SelectPtrOrArr = 1;
290 }
291 // Note: The `Decl::isFlexibleArrayMemberLike` check earlier on means
292 // only `PointeeTy->isStructureTypeWithFlexibleArrayMember()` is reachable
293 // when `FieldTy->isArrayType()`.
294 bool ShouldWarn = false;
295 if (!CountInBytes && PointeeTy->isAlwaysIncompleteType()) {
296 // In general using `counted_by` or `counted_by_or_null` on
297 // pointers where the pointee is an incomplete type are problematic. This is
298 // because it isn't possible to compute the pointer's bounds without knowing
299 // the pointee type size. At the same time it is common to forward declare
300 // types in header files.
301 //
302 // E.g.:
303 //
304 // struct Handle;
305 // struct Wrapper {
306 // size_t count;
307 // struct Handle* __counted_by(count) handles;
308 // }
309 //
310 // To allow the above code pattern but still prevent the pointee type from
311 // being incomplete in places where bounds checks are needed the following
312 // scheme is used:
313 //
314 // * When the pointee type might not always be an incomplete type (i.e.
315 // a type that is currently incomplete but might be completed later
316 // on in the translation unit) the attribute is allowed by this method
317 // but later uses of the FieldDecl are checked that the pointee type
318 // is complete see `BoundsSafetyCheckAssignmentToCountAttrPtr`,
319 // `BoundsSafetyCheckInitialization`, and
320 // `BoundsSafetyCheckUseOfCountAttrPtr`
321 //
322 // * When the pointee type is always an incomplete type (e.g.
323 // `void` in strict C mode) the attribute is disallowed by this method
324 // because we know the type can never be completed so there's no reason
325 // to allow it.
326 //
327 // Exception: void has an implicit size of 1 byte for pointer arithmetic
328 // (following GNU convention). Therefore, counted_by on void* is allowed
329 // and behaves equivalently to sized_by (treating the count as bytes).
330 bool IsVoidPtr = PointeeTy->isVoidType();
331 if (IsVoidPtr) {
332 // Emit a warning that this is a GNU extension.
333 Diag(Loc: FD->getBeginLoc(), DiagID: diag::ext_gnu_counted_by_void_ptr) << Kind;
334 Diag(Loc: FD->getBeginLoc(), DiagID: diag::note_gnu_counted_by_void_ptr_use_sized_by)
335 << Kind;
336 assert(InvalidTypeKind == CountedByInvalidPointeeTypeKind::VALID);
337 } else {
338 InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
339 }
340 } else if (PointeeTy->isSizelessType()) {
341 InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
342 } else if (PointeeTy->isFunctionType()) {
343 InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION;
344 } else if (!CountInBytes &&
345 PointeeTy->isStructureTypeWithFlexibleArrayMember()) {
346 if (FieldTy->isArrayType() && !getLangOpts().BoundsSafety) {
347 // This is a workaround for the Linux kernel that has already adopted
348 // `counted_by` on a FAM where the pointee is a struct with a FAM. This
349 // should be an error because computing the bounds of the array cannot be
350 // done correctly without manually traversing every struct object in the
351 // array at runtime. To allow the code to be built this error is
352 // downgraded to a warning.
353 ShouldWarn = true;
354 }
355 InvalidTypeKind = CountedByInvalidPointeeTypeKind::FLEXIBLE_ARRAY_MEMBER;
356 }
357
358 if (InvalidTypeKind != CountedByInvalidPointeeTypeKind::VALID) {
359 unsigned DiagID = ShouldWarn
360 ? diag::warn_counted_by_attr_elt_type_unknown_size
361 : diag::err_counted_by_attr_pointee_unknown_size;
362 Diag(Loc: FD->getBeginLoc(), DiagID)
363 << SelectPtrOrArr << PointeeTy << (int)InvalidTypeKind
364 << (ShouldWarn ? 1 : 0) << Kind << FD->getSourceRange();
365 return true;
366 }
367
368 // Check the expression
369
370 if (!E->getType()->isIntegerType() || E->getType()->isBooleanType()) {
371 Diag(Loc: E->getBeginLoc(), DiagID: diag::err_count_attr_argument_not_integer)
372 << Kind << E->getSourceRange();
373 return true;
374 }
375
376 auto *DRE = dyn_cast<DeclRefExpr>(Val: E);
377 if (!DRE) {
378 Diag(Loc: E->getBeginLoc(),
379 DiagID: diag::err_count_attr_only_support_simple_decl_reference)
380 << Kind << E->getSourceRange();
381 return true;
382 }
383
384 auto *CountDecl = DRE->getDecl();
385 FieldDecl *CountFD = dyn_cast<FieldDecl>(Val: CountDecl);
386 if (auto *IFD = dyn_cast<IndirectFieldDecl>(Val: CountDecl)) {
387 CountFD = IFD->getAnonField();
388 }
389 if (!CountFD) {
390 Diag(Loc: E->getBeginLoc(), DiagID: diag::err_count_attr_must_be_in_structure)
391 << CountDecl << Kind << E->getSourceRange();
392
393 Diag(Loc: CountDecl->getBeginLoc(),
394 DiagID: diag::note_flexible_array_counted_by_attr_field)
395 << CountDecl << CountDecl->getSourceRange();
396 return true;
397 }
398
399 if (FD->getParent() != CountFD->getParent()) {
400 if (CountFD->getParent()->isUnion()) {
401 Diag(Loc: CountFD->getBeginLoc(), DiagID: diag::err_count_attr_refer_to_union)
402 << Kind << CountFD->getSourceRange();
403 return true;
404 }
405 // Whether CountRD is an anonymous struct is not determined at this
406 // point. Thus, an additional diagnostic in case it's not anonymous struct
407 // is done later in `Parser::ParseStructDeclaration`.
408 auto *RD = GetEnclosingNamedOrTopAnonRecord(FD);
409 auto *CountRD = GetEnclosingNamedOrTopAnonRecord(FD: CountFD);
410
411 if (RD != CountRD) {
412 Diag(Loc: E->getBeginLoc(), DiagID: diag::err_count_attr_param_not_in_same_struct)
413 << CountFD << Kind << FieldTy->isArrayType() << E->getSourceRange();
414 Diag(Loc: CountFD->getBeginLoc(),
415 DiagID: diag::note_flexible_array_counted_by_attr_field)
416 << CountFD << CountFD->getSourceRange();
417 return true;
418 }
419 }
420 return false;
421}
422
423static void EmitIncompleteCountedByPointeeNotes(Sema &S,
424 const CountAttributedType *CATy,
425 NamedDecl *IncompleteTyDecl) {
426 assert(IncompleteTyDecl == nullptr || isa<TypeDecl>(IncompleteTyDecl));
427
428 if (IncompleteTyDecl) {
429 // Suggest completing the pointee type if its a named typed (i.e.
430 // IncompleteTyDecl isn't nullptr). Suggest this first as it is more likely
431 // to be the correct fix.
432 //
433 // Note the `IncompleteTyDecl` type is the underlying type which might not
434 // be the same as `CATy->getPointeeType()` which could be a typedef.
435 //
436 // The diagnostic printed will be at the location of the underlying type but
437 // the diagnostic text will print the type of `CATy->getPointeeType()` which
438 // could be a typedef name rather than the underlying type. This is ok
439 // though because the diagnostic will print the underlying type name too.
440 S.Diag(Loc: IncompleteTyDecl->getBeginLoc(),
441 DiagID: diag::note_counted_by_consider_completing_pointee_ty)
442 << CATy->getPointeeType();
443 }
444
445 // Suggest using __sized_by(_or_null) instead of __counted_by(_or_null) as
446 // __sized_by(_or_null) doesn't have the complete type restriction.
447 //
448 // We use the source range of the expression on the CountAttributedType as an
449 // approximation for the source range of the attribute. This isn't quite right
450 // but isn't easy to fix right now.
451 //
452 // TODO: Implement logic to find the relevant TypeLoc for the attribute and
453 // get the SourceRange from that (#113582).
454 //
455 // TODO: We should emit a fix-it here.
456 SourceRange AttrSrcRange = CATy->getCountExpr()->getSourceRange();
457 S.Diag(Loc: AttrSrcRange.getBegin(), DiagID: diag::note_counted_by_consider_using_sized_by)
458 << CATy->isOrNull() << AttrSrcRange;
459}
460
461static std::tuple<const CountAttributedType *, QualType>
462GetCountedByAttrOnIncompletePointee(QualType Ty, NamedDecl **ND) {
463 auto *CATy = Ty->getAs<CountAttributedType>();
464 // Incomplete pointee type is only a problem for
465 // counted_by/counted_by_or_null
466 if (!CATy || CATy->isCountInBytes())
467 return {};
468
469 auto PointeeTy = CATy->getPointeeType();
470 if (PointeeTy.isNull()) {
471 // Reachable if `CountAttributedType` wraps an IncompleteArrayType
472 return {};
473 }
474
475 if (!PointeeTy->isIncompleteType(Def: ND))
476 return {};
477
478 if (PointeeTy->isVoidType())
479 return {};
480
481 return {CATy, PointeeTy};
482}
483
484/// Perform Checks for assigning to a `__counted_by` or
485/// `__counted_by_or_null` pointer type \param LHSTy where the pointee type
486/// is incomplete which is invalid.
487///
488/// \param S The Sema instance.
489/// \param LHSTy The type being assigned to. Checks will only be performed if
490/// the type is a `counted_by` or `counted_by_or_null ` pointer.
491/// \param RHSExpr The expression being assigned from.
492/// \param Action The type assignment being performed
493/// \param Loc The SourceLocation to use for error diagnostics
494/// \param Assignee The ValueDecl being assigned. This is used to compute
495/// the name of the assignee. If the assignee isn't known this can
496/// be set to nullptr.
497/// \param ShowFullyQualifiedAssigneeName If set to true when using \p
498/// Assignee to compute the name of the assignee use the fully
499/// qualified name, otherwise use the unqualified name.
500///
501/// \returns True iff no diagnostic where emitted, false otherwise.
502static bool CheckAssignmentToCountAttrPtrWithIncompletePointeeTy(
503 Sema &S, QualType LHSTy, Expr *RHSExpr, AssignmentAction Action,
504 SourceLocation Loc, const ValueDecl *Assignee,
505 bool ShowFullyQualifiedAssigneeName) {
506 NamedDecl *IncompleteTyDecl = nullptr;
507 auto [CATy, PointeeTy] =
508 GetCountedByAttrOnIncompletePointee(Ty: LHSTy, ND: &IncompleteTyDecl);
509 if (!CATy)
510 return true;
511
512 std::string AssigneeStr;
513 if (Assignee) {
514 if (ShowFullyQualifiedAssigneeName) {
515 AssigneeStr = Assignee->getQualifiedNameAsString();
516 } else {
517 AssigneeStr = Assignee->getNameAsString();
518 }
519 }
520
521 S.Diag(Loc, DiagID: diag::err_counted_by_on_incomplete_type_on_assign)
522 << static_cast<int>(Action) << AssigneeStr << (AssigneeStr.size() > 0)
523 << isa<ImplicitValueInitExpr>(Val: RHSExpr) << LHSTy
524 << CATy->getAttributeName(/*WithMacroPrefix=*/true) << PointeeTy
525 << CATy->isOrNull() << RHSExpr->getSourceRange();
526
527 EmitIncompleteCountedByPointeeNotes(S, CATy, IncompleteTyDecl);
528 return false; // check failed
529}
530
531bool Sema::BoundsSafetyCheckAssignmentToCountAttrPtr(
532 QualType LHSTy, Expr *RHSExpr, AssignmentAction Action, SourceLocation Loc,
533 const ValueDecl *Assignee, bool ShowFullyQualifiedAssigneeName) {
534 return CheckAssignmentToCountAttrPtrWithIncompletePointeeTy(
535 S&: *this, LHSTy, RHSExpr, Action, Loc, Assignee,
536 ShowFullyQualifiedAssigneeName);
537}
538
539bool Sema::BoundsSafetyCheckInitialization(const InitializedEntity &Entity,
540 const InitializationKind &Kind,
541 AssignmentAction Action,
542 QualType LHSType, Expr *RHSExpr) {
543 auto SL = Kind.getLocation();
544
545 // Note: We don't call `BoundsSafetyCheckAssignmentToCountAttrPtr` here
546 // because we need conditionalize what is checked. In downstream
547 // Clang `counted_by` is supported on variable definitions and in that
548 // implementation an error diagnostic will be emitted on the variable
549 // definition if the pointee is an incomplete type. To avoid warning about the
550 // same problem twice (once when the variable is defined, once when Sema
551 // checks the initializer) we skip checking the initializer if it's a
552 // variable.
553 if (Action == AssignmentAction::Initializing &&
554 Entity.getKind() != InitializedEntity::EK_Variable) {
555
556 if (!CheckAssignmentToCountAttrPtrWithIncompletePointeeTy(
557 S&: *this, LHSTy: LHSType, RHSExpr, Action, Loc: SL,
558 Assignee: dyn_cast_or_null<ValueDecl>(Val: Entity.getDecl()),
559 /*ShowFullQualifiedAssigneeName=*/ShowFullyQualifiedAssigneeName: true)) {
560 return false;
561 }
562 }
563
564 return true;
565}
566
567bool Sema::BoundsSafetyCheckUseOfCountAttrPtr(const Expr *E) {
568 QualType T = E->getType();
569 if (!T->isPointerType())
570 return true;
571
572 NamedDecl *IncompleteTyDecl = nullptr;
573 auto [CATy, PointeeTy] =
574 GetCountedByAttrOnIncompletePointee(Ty: T, ND: &IncompleteTyDecl);
575 if (!CATy)
576 return true;
577
578 // Generate a string for the diagnostic that describes the "use".
579 // The string is specialized for direct calls to produce a better
580 // diagnostic.
581 SmallString<64> UseStr;
582 bool IsDirectCall = false;
583 if (const auto *CE = dyn_cast<CallExpr>(Val: E->IgnoreParens())) {
584 if (const auto *FD = CE->getDirectCallee()) {
585 UseStr = FD->getName();
586 IsDirectCall = true;
587 }
588 }
589
590 if (!IsDirectCall) {
591 llvm::raw_svector_ostream SS(UseStr);
592 E->printPretty(OS&: SS, Helper: nullptr, Policy: getPrintingPolicy());
593 }
594
595 Diag(Loc: E->getBeginLoc(), DiagID: diag::err_counted_by_on_incomplete_type_on_use)
596 << IsDirectCall << UseStr << T << PointeeTy
597 << CATy->getAttributeName(/*WithMacroPrefix=*/true) << CATy->isOrNull()
598 << E->getSourceRange();
599
600 EmitIncompleteCountedByPointeeNotes(S&: *this, CATy, IncompleteTyDecl);
601 return false;
602}
603
604} // namespace clang
605