[clang] fc92154 - [BoundsSafety][NFC] Build an incomplete CountAttributedType for a late-parsed attribute (#224558)

via cfe-commits cfe-commits at lists.llvm.org
Wed Oct 21 11:45:53 PDT 2026


Author: Yeoul Na
Date: 2026-10-21T11:45:46-07:00
New Revision: fc9215428138c4d9238486c2bdbea192b6107b65

URL: https://github.com/llvm/llvm-project/commit/fc9215428138c4d9238486c2bdbea192b6107b65
DIFF: https://github.com/llvm/llvm-project/commit/fc9215428138c4d9238486c2bdbea192b6107b65.diff

LOG: [BoundsSafety][NFC] Build an incomplete CountAttributedType for a late-parsed attribute (#224558)

This is part of supporting late parsing of counted_by as a type
attribute, following the direction set in
https://github.com/llvm/llvm-project/pull/223267, which allows a
CountAttributedType's count to be filled in later.

Add Sema::ProcessLateParsedTypeAttr. It validates a late-parsed
counted_by-family attribute in type position and wraps the type in a
CountAttributedType whose count is filled in once the enclosing record
is complete.
    
LateParsedTypeAttribute is owned by the Parser, which Sema cannot depend
on. Sema therefore reads the attribute's kind, location and type slot
through a callback.
    
No functional change: nothing creates late-parsed type attributes yet,
so ProcessLateParsedTypeAttr is never invoked. The next commit wires it
up.
    
Assisted-by: Opus 5.5

Added: 
    

Modified: 
    clang/include/clang/Parse/Parser.h
    clang/include/clang/Sema/DeclSpec.h
    clang/include/clang/Sema/Sema.h
    clang/lib/Parse/ParseDecl.cpp
    clang/lib/Sema/SemaType.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 7f91c7d4670ff1..4e1271da82861b 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -237,19 +237,12 @@ struct LateParsedAttribute : public LateParsedDeclaration {
 /// is replaced with a concrete type (e.g., CountAttributedType).
 struct LateParsedTypeAttribute : public LateParsedAttribute {
 
-  /// The type built for this attribute during type construction, still missing
-  /// the argument that hasn't been parsed yet. Filled in by
-  /// `Parser::ProcessLateParsedTypeAttrCallback` and completed once the
-  /// enclosing scope makes the argument parseable. Null if type construction
-  /// rejected the attribute.
-  ///
-  /// Held as the base class so the parser stays agnostic about which bounds
-  /// attribute this is; Sema dispatches on the concrete kind when completing.
-  BoundsAttributedType *TypeToComplete = nullptr;
-
-  explicit LateParsedTypeAttribute(Parser *P, IdentifierInfo &Name,
-                                   SourceLocation Loc)
-      : LateParsedAttribute(P, Name, Loc, Kind::Type) {}
+  /// What Sema reads and fills in during type construction.
+  LateParsedTypeAttrInfo Info;
+
+  LateParsedTypeAttribute(Parser *P, IdentifierInfo &Name, SourceLocation Loc,
+                          ParsedAttr::Kind AttrKind)
+      : LateParsedAttribute(P, Name, Loc, Kind::Type), Info(AttrKind, Loc) {}
 
   void ParseLexedAttributes() override;
 

diff  --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h
index 66a6098a75ae9b..7b58bfcf53d98a 100644
--- a/clang/include/clang/Sema/DeclSpec.h
+++ b/clang/include/clang/Sema/DeclSpec.h
@@ -40,6 +40,7 @@
 
 namespace clang {
   class ASTContext;
+  class BoundsAttributedType;
   class CXXRecordDecl;
   class TypeLoc;
   class LangOptions;
@@ -1283,6 +1284,27 @@ class LateParsedAttrList : public SmallVector<LateParsedAttribute *, 2> {
   bool LateAttrParseTypeAttrOnly;
 };
 
+/// The part of a late-parsed type attribute that Sema reads and fills in during
+/// type construction. The parser owns the attribute and its cached tokens and
+/// embeds this, so Sema never needs to see the parser's type.
+struct LateParsedTypeAttrInfo {
+  ParsedAttr::Kind Kind;
+  SourceLocation NameLoc;
+
+  /// The type built for this attribute during type construction, still missing
+  /// the argument that hasn't been parsed yet. Filled in by
+  /// `Sema::ProcessLateParsedTypeAttr` and completed once the enclosing scope
+  /// makes the argument parseable. Null if type construction rejected the
+  /// attribute.
+  ///
+  /// Held as the base class so the parser stays agnostic about which bounds
+  /// attribute this is; Sema dispatches on the concrete kind when completing.
+  BoundsAttributedType *TypeToComplete = nullptr;
+
+  LateParsedTypeAttrInfo(ParsedAttr::Kind Kind, SourceLocation NameLoc)
+      : Kind(Kind), NameLoc(NameLoc) {}
+};
+
 /// One instance of this struct is used for each type in a
 /// declarator that is parsed.
 ///

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 3172f9b2d7eaab..9082042c48502d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -2601,10 +2601,15 @@ class Sema final : public SemaBase {
     return RejectedLateParsedBoundsTypes.contains(BATy);
   }
 
+  /// Validate the late-parsed type attribute \p LA and wrap \p QT in a
+  /// CountAttributedType with no count yet, recorded on \p LA for later
+  /// completion. Returns false if \p LA is invalid.
+  bool ProcessLateParsedTypeAttr(LateParsedTypeAttrInfo &LA, QualType &QT);
+
   /// Supply the parsed argument of a late-parsed bounds attribute to the type
-  /// built for it by ActOnLateParsedTypeAttr, and run the checks that need the
-  /// owning declaration. \p FD is the field the type belongs to. Returns false
-  /// if the attribute was rejected.
+  /// built for it by ProcessLateParsedTypeAttr, and run the checks that need
+  /// the owning declaration. \p FD is the field the type belongs to. Returns
+  /// false if the attribute was rejected.
   bool ActOnLateParsedTypeAttrArgument(BoundsAttributedType *BATy,
                                        FieldDecl *FD, Expr *Arg);
 

diff  --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 5b76b5d2ef274b..ada54c85695c34 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -4948,7 +4948,7 @@ void Parser::CompleteLateParsedTypeAttributes(
   for (LateParsedTypeAttribute *RawLTA : LateTypeAttrs) {
     std::unique_ptr<LateParsedTypeAttribute> LTA(RawLTA);
 
-    BoundsAttributedType *BATy = LTA->TypeToComplete;
+    BoundsAttributedType *BATy = LTA->Info.TypeToComplete;
     if (!BATy || Actions.isLateParsedBoundsTypeRejected(BATy))
       continue;
 

diff  --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp
index 3d444bfabc8c39..af0403e73480c0 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -9072,6 +9072,30 @@ static void HandleHLSLParamModifierAttr(TypeProcessingState &State,
   }
 }
 
+bool Sema::ProcessLateParsedTypeAttr(LateParsedTypeAttrInfo &LA, QualType &QT) {
+  // A DeclSpec attribute runs this once per declarator, as in
+  // `IP __counted_by(n) a, b;`. Reuse one node, as the eager path does, so no
+  // node is left without a count.
+  if (LA.TypeToComplete) {
+    QT = QualType(LA.TypeToComplete, 0);
+    return true;
+  }
+
+  // Nesting is checked once the enclosing declarator chunks wrap the node.
+  BoundsAttrFlags Flags;
+  if (!ValidateBoundsAttrTypeForTypePosition(QT, LA.Kind, LA.NameLoc,
+                                             SourceRange(LA.NameLoc),
+                                             /*PointerNestLevel=*/0, Flags))
+    return false;
+
+  // The argument isn't parsed yet, so build the type without a count.
+  CountAttributedType *CATy = getASTContext().getIncompleteCountAttributedType(
+      QT, Flags.CountInBytes, Flags.OrNull);
+  QT = QualType(CATy, 0);
+  LA.TypeToComplete = CATy;
+  return true;
+}
+
 static void processTypeAttrs(TypeProcessingState &state, QualType &type,
                              TypeAttrLocation TAL,
                              const ParsedAttributesView &attrs,


        


More information about the cfe-commits mailing list