[clang] [BoundsSafety][NFC] Add counted_by type-shape validation helper (PR #227774)

Yeoul Na via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 2 10:47:05 PDT 2026


================
@@ -49,6 +77,123 @@ enum class CountedByInvalidPointeeTypeKind {
   VALID,
 };
 
+/// Check type conflicts under the -fbounds-safety attribute model.
+/// Return std::nullopt if validation should continue with the shared checks.
+static std::optional<bool> checkBoundsAttrTypeConflictsAndMisc(
+    Sema &S, QualType Ty, SourceLocation AttrLoc,
+    const Sema::BoundsAttrFlags &Flags, StringRef AttrSpelling,
+    bool AllowRedecl, Expr *AttrArg) {
+  // The -fbounds-safety model's checks for conflicting attributes, atomic
+  // pointers and array shapes are not upstream yet.
+  return std::nullopt;
+}
+
+bool Sema::ValidateBoundsAttrTypeShape(QualType Ty, SourceLocation AttrLoc,
+                                       SourceRange AttrRange,
+                                       BoundsAttrFlags &Flags,
+                                       StringRef AttrSpelling, bool AllowRedecl,
+                                       Expr *AttrArg, bool UpdateFlags) {
+  if (getLangOpts().hasBoundsSafetyAttributes())
+    if (std::optional<bool> Result = checkBoundsAttrTypeConflictsAndMisc(
+            *this, Ty, AttrLoc, Flags, AttrSpelling, AllowRedecl, AttrArg))
+      return *Result;
+
+  BoundsAttributedType::BoundsAttrKind Kind = getBoundsAttrKind(Flags);
+
+  // counted_by and sized_by require a pointer or array.
+  if (!Ty->isPointerType() && !Ty->isArrayType()) {
+    Diag(AttrLoc, diag::err_count_attr_not_on_ptr_or_flexible_array_member)
+        << Kind << 0;
+    return false;
+  }
+
+  // Arrays only support counted_by outside the -fbounds-safety attribute model.
+  if (!getLangOpts().hasBoundsSafetyAttributes() && Ty->isArrayType() &&
+      (Flags.CountInBytes || Flags.OrNull)) {
+    Diag(AttrLoc, diag::err_count_attr_not_on_ptr_or_flexible_array_member)
+        << Kind << /*suggest counted_by*/ 1;
+    return false;
+  }
+
+  // Check the pointee or element type.
+  QualType PointeeTy;
+  int SelectPtrOrArr;
+  if (Ty->isPointerType()) {
+    PointeeTy = Ty->getPointeeType();
+    SelectPtrOrArr = 0;
+  } else {
+    const ArrayType *AT = getASTContext().getAsArrayType(Ty);
+    PointeeTy = AT->getElementType();
+    SelectPtrOrArr = 1;
+  }
+
+  auto InvalidTypeKind = CountedByInvalidPointeeTypeKind::VALID;
+  bool ShouldWarn = false;
+  if (!Flags.CountInBytes && PointeeTy->isAlwaysIncompleteType()) {
+    // GNU void pointer arithmetic treats each element as one byte, so allow
+    // counted_by on void pointers outside the -fbounds-safety attribute model.
+    if (PointeeTy->isVoidType() && !getLangOpts().hasBoundsSafetyAttributes()) {
+      Diag(AttrLoc, diag::ext_gnu_counted_by_void_ptr) << Kind;
+      Diag(AttrLoc, diag::note_gnu_counted_by_void_ptr_use_sized_by) << Kind;
+      if (UpdateFlags)
+        Flags.CountInBytes = true;
+      return true;
+    }
+    InvalidTypeKind = CountedByInvalidPointeeTypeKind::INCOMPLETE;
+  } else if (PointeeTy->isSizelessType()) {
+    InvalidTypeKind = CountedByInvalidPointeeTypeKind::SIZELESS;
+  } else if (PointeeTy->isFunctionType()) {
+    InvalidTypeKind = CountedByInvalidPointeeTypeKind::FUNCTION;
+  } else if (!Flags.CountInBytes &&
+             PointeeTy->isStructureTypeWithFlexibleArrayMember()) {
+    if (Ty->isArrayType() && !getLangOpts().BoundsSafety) {
----------------
rapidsna wrote:

Let's take the change in downstream: https://github.com/swiftlang/llvm-project/pull/14186/changes#diff-b622d95f208dd56aed93b32de4a0189e8dac608cab6288fafa943e51059be217R350

https://github.com/llvm/llvm-project/pull/227774


More information about the cfe-commits mailing list