https://github.com/rapidsna updated https://github.com/llvm/llvm-project/pull/224558
>From 8d201af8054c58d8e454cc7a368d9bfdc037ee68 Mon Sep 17 00:00:00 2001 From: Yeoul Na <[email protected]> Date: Thu, 17 Sep 2026 21:12:37 -0700 Subject: [PATCH] [BoundsSafety][NFC] Add the Sema/Parser bridge for late-parsed type attributes A late-parsed bounds attribute has to build its type when the attribute is seen, but its argument isn't parseable until the enclosing record is complete. Building that type needs the Parser (which owns the cached tokens) and Sema (which owns type construction) to meet: - Sema::ActOnLateParsedTypeAttr validates a counted_by-family attribute for the type position and, if valid, wraps the type in a CountAttributedType whose count is not yet known, handing the node back for completion. - Parser::ProcessLateParsedTypeAttrCallback is the Parser-side entry point, registered on Sema so Sema can call back without including Parser.h (the same pattern as LateTemplateParserCallback). It reuses an already-built node so several declarators sharing one attribute share one type. No functional change: nothing records late-parsed type attributes yet, so the callback is never invoked. The next commit wires it up. --- clang/include/clang/Parse/Parser.h | 14 +++++++++++++ clang/include/clang/Sema/Sema.h | 21 ++++++++++++++++++++ clang/lib/Parse/ParseDecl.cpp | 32 ++++++++++++++++++++++++++++++ clang/lib/Parse/Parser.cpp | 5 +++++ clang/lib/Sema/SemaType.cpp | 21 ++++++++++++++++++++ 5 files changed, 93 insertions(+) diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index ce97ad25bcd16..ae7c345ba6ce3 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -8153,6 +8153,20 @@ class Parser : public CodeCompletionHandler { static void LateTemplateParserCallback(void *P, LateParsedTemplate &LPT); + /// Validate \p LA as a late-parsed type attribute and, if valid, wrap \p type + /// in a \c CountAttributedType whose count expression is not yet known, + /// recording the node on \p LA so it can be completed later. + /// + /// \p LA is downcast to \c LateParsedTypeAttribute; if the cast fails the + /// attribute is not applicable here and the function returns \c true to skip. + /// \p pointerNestLevel is the number of pointer/array/function declarator + /// chunks that precede the current chunk (see \c getPointerNestLevel). + /// Returns \c true on success and \c false if the attribute is invalid for + /// \p type. + static bool ProcessLateParsedTypeAttrCallback(LateParsedAttribute *LA, + QualType &type, + unsigned pointerNestLevel); + /// We've parsed something that could plausibly be intended to be a template /// name (\p LHS) followed by a '<' token, and the following code can't /// possibly be an expression. Determine if this is likely to be a template-id diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 8fb985423c4a4..aa18627776da8 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -1354,6 +1354,27 @@ class Sema final : public SemaBase { OpaqueParser = P; } + /// Callback to the parser to interact with late-parsed type attributes. This + /// allows Sema to call back into Parser without including Parser.h. + /// + /// Processes a single late-parsed type attribute: validates the attribute + /// kind/type and wraps \p type in a CountAttributedType whose count is not + /// yet known, if appropriate. Returns false if the attribute is invalid. + typedef bool ProcessLateParsedTypeAttrCB(LateParsedAttribute *LA, + QualType &type, + unsigned pointerNestLevel); + ProcessLateParsedTypeAttrCB *ProcessLateParsedTypeAttrCallback = nullptr; + + /// Called from the Parser's ProcessLateParsedTypeAttrCallback to validate a + /// counted_by-family attribute type and, if valid, wrap \p type in a + /// CountAttributedType whose count expression is not yet known. Returns false + /// if the attribute should be dropped, otherwise sets \p BATy to the node the + /// caller must complete once the argument is parseable. + bool ActOnLateParsedTypeAttr(ParsedAttr::Kind AttrKind, + SourceLocation AttrNameLoc, QualType &type, + unsigned pointerNestLevel, + BoundsAttributedType **BATy); + /// Callback to the parser to parse a type expressed as a string. std::function<TypeResult(StringRef, StringRef, SourceLocation)> ParseTypeFromStringCallback; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e3b0eda1af670..dd2d0e1a5136d 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -4896,6 +4896,38 @@ void Parser::ParseLexedTypeAttribute(LateParsedTypeAttribute &LA, OutAttrs.takeAllAppendingFrom(Attrs); } +bool Parser::ProcessLateParsedTypeAttrCallback(LateParsedAttribute *LA, + QualType &type, + unsigned pointerNestLevel) { + auto *LTA = dyn_cast_if_present<LateParsedTypeAttribute>(LA); + if (!LTA) + return true; + + // One attribute yields one type node, even when several declarators share it. + // A declaration-specifier-position attribute lives on the DeclSpec, whose + // late-attribute list ConvertDeclSpecToType walks once per declarator, so + // this callback runs N times for `IP __counted_by(n) a, b;`. Building a fresh + // (deliberately un-uniqued) node each time would leave every node but the + // last orphaned with a null count, so reuse the node instead. This matches + // the eager path, where getCountAttributedType uniques on the count + // expression and all declarators likewise share one node. + if (LTA->TypeToComplete) { + type = QualType(LTA->TypeToComplete, 0); + return true; + } + + ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind( + <A->AttrName, nullptr, ParsedAttr::Form::GNU().getSyntax()); + // Sema cannot see LateParsedTypeAttribute's definition, so it hands the node + // back and we record it here for the completion pass to fill in. + BoundsAttributedType *BATy = nullptr; + if (!LTA->Self->Actions.ActOnLateParsedTypeAttr( + AttrKind, LTA->AttrNameLoc, type, pointerNestLevel, &BATy)) + return false; + LTA->TypeToComplete = BATy; + return true; +} + void Parser::CompleteLateParsedTypeAttributes( SmallVectorImpl<LateParsedTypeAttribute *> &LateTypeAttrs) { for (LateParsedTypeAttribute *RawLTA : LateTypeAttrs) { diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index c86ed6b2ea3f9..2d1fcffcf5e4e 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -592,6 +592,11 @@ void Parser::Initialize() { } Actions.Initialize(); + // Register the callback so Sema can call back into the Parser to handle + // late-parsed type attributes (e.g. counted_by on struct fields), which + // may be processed at any point during parsing via ActOnFields. + Actions.ProcessLateParsedTypeAttrCallback = + &Parser::ProcessLateParsedTypeAttrCallback; // Prime the lexer look-ahead. ConsumeToken(); diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7f649a601ee44..d5ac7e9fd6dd4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -9124,6 +9124,27 @@ static bool validateBoundsAttrTypeForTypePosition( return true; } +bool Sema::ActOnLateParsedTypeAttr(ParsedAttr::Kind AttrKind, + SourceLocation AttrNameLoc, QualType &type, + unsigned pointerNestLevel, + BoundsAttributedType **BATy) { + BoundsAttrFlags Flags; + if (!validateBoundsAttrTypeForTypePosition(*this, type, AttrKind, AttrNameLoc, + SourceRange(AttrNameLoc), + pointerNestLevel, Flags)) + return false; + + // The argument hasn't been parsed yet, so build the type without it and hand + // the node back for completion. Because enclosing types refer to it by + // pointer, filling the argument in later leaves them untouched — no rebuild + // of the type chain and no TypeLoc re-emission. + auto *CATy = getASTContext().getIncompleteCountAttributedType( + type, Flags.CountInBytes, Flags.OrNull); + type = QualType(CATy, 0); + *BATy = CATy; + return true; +} + static void processTypeAttrs(TypeProcessingState &state, QualType &type, TypeAttrLocation TAL, const ParsedAttributesView &attrs, _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
