[clang] [clang][NFC] Regroup declarations in `Parser` (PR #138511)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 5 04:51:45 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Vlad Serebrennikov (Endilll)
<details>
<summary>Changes</summary>
Following the steps of #<!-- -->82217, this patch reorganizes declarations in `Parse.h`. Highlights are:
1) Declarations are grouped in the same fashion as in `Sema.h`. Table of contents is provided at the beginning of `Parser` class. `public` declaration go first, then `private` ones, but unlike `Sema`, most of the stuff in `Parser` is private.
2) Documentation has been moved from `.cpp` files to the header. Grammar was consistently put in `\verbatim` blocks to render nicely in Doxygen.
3) File has been formatted with clang-format, except for the grammar, because clang-format butchers it.
---
Patch is 731.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/138511.diff
16 Files Affected:
- (modified) clang/include/clang/Parse/Parser.h (+7898-3021)
- (modified) clang/lib/Parse/ParseCXXInlineMethods.cpp (-52)
- (modified) clang/lib/Parse/ParseDecl.cpp (-566)
- (modified) clang/lib/Parse/ParseDeclCXX.cpp (-419)
- (modified) clang/lib/Parse/ParseExpr.cpp (-543)
- (modified) clang/lib/Parse/ParseExprCXX.cpp (-526)
- (modified) clang/lib/Parse/ParseInit.cpp (-61)
- (modified) clang/lib/Parse/ParseObjc.cpp (-376)
- (modified) clang/lib/Parse/ParseOpenACC.cpp (-57)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (-348)
- (modified) clang/lib/Parse/ParsePragma.cpp (-10)
- (modified) clang/lib/Parse/ParseStmt.cpp (-240)
- (modified) clang/lib/Parse/ParseStmtAsm.cpp (-58)
- (modified) clang/lib/Parse/ParseTemplate.cpp (-233)
- (modified) clang/lib/Parse/ParseTentative.cpp (+1-395)
- (modified) clang/lib/Parse/Parser.cpp (+2-203)
``````````diff
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 00e4b980bf44a..ab6927130bc2b 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -29,28 +29,28 @@
#include <stack>
namespace clang {
- class PragmaHandler;
- class Scope;
- class BalancedDelimiterTracker;
- class CorrectionCandidateCallback;
- class DeclGroupRef;
- class DiagnosticBuilder;
- struct LoopHint;
- class Parser;
- class ParsingDeclRAIIObject;
- class ParsingDeclSpec;
- class ParsingDeclarator;
- class ParsingFieldDeclarator;
- class ColonProtectionRAIIObject;
- class InMessageExpressionRAIIObject;
- class PoisonSEHIdentifiersRAIIObject;
- class OMPClause;
- class OpenACCClause;
- class ObjCTypeParamList;
- struct OMPTraitProperty;
- struct OMPTraitSelector;
- struct OMPTraitSet;
- class OMPTraitInfo;
+class PragmaHandler;
+class Scope;
+class BalancedDelimiterTracker;
+class CorrectionCandidateCallback;
+class DeclGroupRef;
+class DiagnosticBuilder;
+struct LoopHint;
+class Parser;
+class ParsingDeclRAIIObject;
+class ParsingDeclSpec;
+class ParsingDeclarator;
+class ParsingFieldDeclarator;
+class ColonProtectionRAIIObject;
+class InMessageExpressionRAIIObject;
+class PoisonSEHIdentifiersRAIIObject;
+class OMPClause;
+class OpenACCClause;
+class ObjCTypeParamList;
+struct OMPTraitProperty;
+struct OMPTraitSelector;
+struct OMPTraitSet;
+class OMPTraitInfo;
enum class AnnotatedNameKind {
/// Annotation has failed and emitted an error.
@@ -153,571 +153,438 @@ enum class CXX11AttributeKind {
/// parsing units of the grammar, productions are invoked to handle whatever has
/// been read.
///
+/// \nosubgrouping
class Parser : public CodeCompletionHandler {
+ // Table of Contents
+ // -----------------
+ // 1. Parsing (Parser.cpp)
+ // 2. C++ Class Inline Methods (ParseCXXInlineMethods.cpp)
+ // 3. Declarations (ParseDecl.cpp)
+ // 4. C++ Declarations (ParseDeclCXX.cpp)
+ // 5. Expressions (ParseExpr.cpp)
+ // 6. C++ Expressions (ParseExprCXX.cpp)
+ // 7. HLSL Constructs (ParseHLSL.cpp)
+ // 8. Initializers (ParseInit.cpp)
+ // 9. Objective-C Constructs (ParseObjc.cpp)
+ // 10. OpenACC Constructs (ParseOpenACC.cpp)
+ // 11. OpenMP Constructs (ParseOpenMP.cpp)
+ // 12. Pragmas (ParsePragma.cpp)
+ // 13. Statements (ParseStmt.cpp)
+ // 14. `inline asm` Statement (ParseStmtAsm.cpp)
+ // 15. C++ Templates (ParseTemplate.cpp)
+ // 16. Tentative Parsing (ParseTentative.cpp)
+
+ /// \name Parsing
+ /// Implementations are in Parser.cpp
+ ///@{
+
+public:
friend class ColonProtectionRAIIObject;
- friend class ParsingOpenMPDirectiveRAII;
- friend class ParsingOpenACCDirectiveRAII;
- friend class InMessageExpressionRAIIObject;
- friend class OffsetOfStateRAIIObject;
friend class PoisonSEHIdentifiersRAIIObject;
- friend class ObjCDeclContextSwitch;
friend class ParenBraceBracketBalancer;
friend class BalancedDelimiterTracker;
- Preprocessor &PP;
+ Parser(Preprocessor &PP, Sema &Actions, bool SkipFunctionBodies);
+ ~Parser() override;
- /// Tok - The current token we are peeking ahead. All parsing methods assume
- /// that this is valid.
- Token Tok;
+ const LangOptions &getLangOpts() const { return PP.getLangOpts(); }
+ const TargetInfo &getTargetInfo() const { return PP.getTargetInfo(); }
+ Preprocessor &getPreprocessor() const { return PP; }
+ Sema &getActions() const { return Actions; }
+ AttributeFactory &getAttrFactory() { return AttrFactory; }
- // PrevTokLocation - The location of the token we previously
- // consumed. This token is used for diagnostics where we expected to
- // see a token following another token (e.g., the ';' at the end of
- // a statement).
- SourceLocation PrevTokLocation;
+ const Token &getCurToken() const { return Tok; }
+ Scope *getCurScope() const { return Actions.getCurScope(); }
- /// Tracks an expected type for the current token when parsing an expression.
- /// Used by code completion for ranking.
- PreferredTypeBuilder PreferredType;
+ void incrementMSManglingNumber() const {
+ return Actions.incrementMSManglingNumber();
+ }
- unsigned short ParenCount = 0, BracketCount = 0, BraceCount = 0;
- unsigned short MisplacedModuleBeginCount = 0;
+ // Type forwarding. All of these are statically 'void*', but they may all be
+ // different actual classes based on the actions in place.
+ typedef OpaquePtr<DeclGroupRef> DeclGroupPtrTy;
+ typedef OpaquePtr<TemplateName> TemplateTy;
- /// Actions - These are the callbacks we invoke as we parse various constructs
- /// in the file.
- Sema &Actions;
+ /// Initialize - Warm up the parser.
+ ///
+ void Initialize();
- DiagnosticsEngine &Diags;
+ /// Parse the first top-level declaration in a translation unit.
+ ///
+ /// \verbatim
+ /// translation-unit:
+ /// [C] external-declaration
+ /// [C] translation-unit external-declaration
+ /// [C++] top-level-declaration-seq[opt]
+ /// [C++20] global-module-fragment[opt] module-declaration
+ /// top-level-declaration-seq[opt] private-module-fragment[opt]
+ /// \endverbatim
+ ///
+ /// Note that in C, it is an error if there is no first declaration.
+ bool ParseFirstTopLevelDecl(DeclGroupPtrTy &Result,
+ Sema::ModuleImportState &ImportState);
- StackExhaustionHandler StackHandler;
+ /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the
+ /// action tells us to. This returns true if the EOF was encountered.
+ ///
+ /// \verbatim
+ /// top-level-declaration:
+ /// declaration
+ /// [C++20] module-import-declaration
+ /// \endverbatim
+ bool ParseTopLevelDecl(DeclGroupPtrTy &Result,
+ Sema::ModuleImportState &ImportState);
+ bool ParseTopLevelDecl() {
+ DeclGroupPtrTy Result;
+ Sema::ModuleImportState IS = Sema::ModuleImportState::NotACXX20Module;
+ return ParseTopLevelDecl(Result, IS);
+ }
- /// ScopeCache - Cache scopes to reduce malloc traffic.
- static constexpr int ScopeCacheSize = 16;
- unsigned NumCachedScopes;
- Scope *ScopeCache[ScopeCacheSize];
+ /// ConsumeToken - Consume the current 'peek token' and lex the next one.
+ /// This does not work with special tokens: string literals, code completion,
+ /// annotation tokens and balanced tokens must be handled using the specific
+ /// consume methods.
+ /// Returns the location of the consumed token.
+ SourceLocation ConsumeToken() {
+ assert(!isTokenSpecial() &&
+ "Should consume special tokens with Consume*Token");
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return PrevTokLocation;
+ }
- /// Identifiers used for SEH handling in Borland. These are only
- /// allowed in particular circumstances
- // __except block
- IdentifierInfo *Ident__exception_code,
- *Ident___exception_code,
- *Ident_GetExceptionCode;
- // __except filter expression
- IdentifierInfo *Ident__exception_info,
- *Ident___exception_info,
- *Ident_GetExceptionInfo;
- // __finally
- IdentifierInfo *Ident__abnormal_termination,
- *Ident___abnormal_termination,
- *Ident_AbnormalTermination;
+ bool TryConsumeToken(tok::TokenKind Expected) {
+ if (Tok.isNot(Expected))
+ return false;
+ assert(!isTokenSpecial() &&
+ "Should consume special tokens with Consume*Token");
+ PrevTokLocation = Tok.getLocation();
+ PP.Lex(Tok);
+ return true;
+ }
- /// Contextual keywords for Microsoft extensions.
- IdentifierInfo *Ident__except;
- mutable IdentifierInfo *Ident_sealed;
- mutable IdentifierInfo *Ident_abstract;
+ bool TryConsumeToken(tok::TokenKind Expected, SourceLocation &Loc) {
+ if (!TryConsumeToken(Expected))
+ return false;
+ Loc = PrevTokLocation;
+ return true;
+ }
- /// Ident_super - IdentifierInfo for "super", to support fast
- /// comparison.
- IdentifierInfo *Ident_super;
- /// Ident_vector, Ident_bool, Ident_Bool - cached IdentifierInfos for "vector"
- /// and "bool" fast comparison. Only present if AltiVec or ZVector are
- /// enabled.
- IdentifierInfo *Ident_vector;
- IdentifierInfo *Ident_bool;
- IdentifierInfo *Ident_Bool;
- /// Ident_pixel - cached IdentifierInfos for "pixel" fast comparison.
- /// Only present if AltiVec enabled.
- IdentifierInfo *Ident_pixel;
+ /// ConsumeAnyToken - Dispatch to the right Consume* method based on the
+ /// current token type. This should only be used in cases where the type of
+ /// the token really isn't known, e.g. in error recovery.
+ SourceLocation ConsumeAnyToken(bool ConsumeCodeCompletionTok = false) {
+ if (isTokenParen())
+ return ConsumeParen();
+ if (isTokenBracket())
+ return ConsumeBracket();
+ if (isTokenBrace())
+ return ConsumeBrace();
+ if (isTokenStringLiteral())
+ return ConsumeStringToken();
+ if (Tok.is(tok::code_completion))
+ return ConsumeCodeCompletionTok ? ConsumeCodeCompletionToken()
+ : handleUnexpectedCodeCompletionToken();
+ if (Tok.isAnnotation())
+ return ConsumeAnnotationToken();
+ return ConsumeToken();
+ }
- /// Objective-C contextual keywords.
- IdentifierInfo *Ident_instancetype;
+ SourceLocation getEndOfPreviousToken() {
+ return PP.getLocForEndOfToken(PrevTokLocation);
+ }
- /// Identifier for "introduced".
- IdentifierInfo *Ident_introduced;
+ /// GetLookAheadToken - This peeks ahead N tokens and returns that token
+ /// without consuming any tokens. LookAhead(0) returns 'Tok', LookAhead(1)
+ /// returns the token after Tok, etc.
+ ///
+ /// Note that this differs from the Preprocessor's LookAhead method, because
+ /// the Parser always has one token lexed that the preprocessor doesn't.
+ ///
+ const Token &GetLookAheadToken(unsigned N) {
+ if (N == 0 || Tok.is(tok::eof))
+ return Tok;
+ return PP.LookAhead(N - 1);
+ }
- /// Identifier for "deprecated".
- IdentifierInfo *Ident_deprecated;
+ /// NextToken - This peeks ahead one token and returns it without
+ /// consuming it.
+ const Token &NextToken() { return PP.LookAhead(0); }
- /// Identifier for "obsoleted".
- IdentifierInfo *Ident_obsoleted;
+ /// getTypeAnnotation - Read a parsed type out of an annotation token.
+ static TypeResult getTypeAnnotation(const Token &Tok) {
+ if (!Tok.getAnnotationValue())
+ return TypeError();
+ return ParsedType::getFromOpaquePtr(Tok.getAnnotationValue());
+ }
- /// Identifier for "unavailable".
- IdentifierInfo *Ident_unavailable;
+ /// TryAnnotateTypeOrScopeToken - If the current token position is on a
+ /// typename (possibly qualified in C++) or a C++ scope specifier not followed
+ /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
+ /// with a single annotation token representing the typename or C++ scope
+ /// respectively.
+ /// This simplifies handling of C++ scope specifiers and allows efficient
+ /// backtracking without the need to re-parse and resolve nested-names and
+ /// typenames.
+ /// It will mainly be called when we expect to treat identifiers as typenames
+ /// (if they are typenames). For example, in C we do not expect identifiers
+ /// inside expressions to be treated as typenames so it will not be called
+ /// for expressions in C.
+ /// The benefit for C/ObjC is that a typename will be annotated and
+ /// Actions.getTypeName will not be needed to be called again (e.g.
+ /// getTypeName will not be called twice, once to check whether we have a
+ /// declaration specifier, and another one to get the actual type inside
+ /// ParseDeclarationSpecifiers).
+ ///
+ /// This returns true if an error occurred.
+ ///
+ /// Note that this routine emits an error if you call it with ::new or
+ /// ::delete as the current tokens, so only call it in contexts where these
+ /// are invalid.
+ bool
+ TryAnnotateTypeOrScopeToken(ImplicitTypenameContext AllowImplicitTypename =
+ ImplicitTypenameContext::No);
- /// Identifier for "message".
- IdentifierInfo *Ident_message;
+ /// Try to annotate a type or scope token, having already parsed an
+ /// optional scope specifier. \p IsNewScope should be \c true unless the scope
+ /// specifier was extracted from an existing tok::annot_cxxscope annotation.
+ bool TryAnnotateTypeOrScopeTokenAfterScopeSpec(
+ CXXScopeSpec &SS, bool IsNewScope,
+ ImplicitTypenameContext AllowImplicitTypename);
- /// Identifier for "strict".
- IdentifierInfo *Ident_strict;
+ /// TryAnnotateScopeToken - Like TryAnnotateTypeOrScopeToken but only
+ /// annotates C++ scope specifiers and template-ids. This returns
+ /// true if there was an error that could not be recovered from.
+ ///
+ /// Note that this routine emits an error if you call it with ::new or
+ /// ::delete as the current tokens, so only call it in contexts where these
+ /// are invalid.
+ bool TryAnnotateCXXScopeToken(bool EnteringContext = false);
- /// Identifier for "replacement".
- IdentifierInfo *Ident_replacement;
+ bool MightBeCXXScopeToken() {
+ return getLangOpts().CPlusPlus &&
+ (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) ||
+ (Tok.is(tok::annot_template_id) &&
+ NextToken().is(tok::coloncolon)) ||
+ Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super));
+ }
+ bool TryAnnotateOptionalCXXScopeToken(bool EnteringContext = false) {
+ return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext);
+ }
- /// Identifier for "environment".
- IdentifierInfo *Ident_environment;
+ //===--------------------------------------------------------------------===//
+ // Scope manipulation
- /// Identifiers used by the 'external_source_symbol' attribute.
- IdentifierInfo *Ident_language, *Ident_defined_in,
- *Ident_generated_declaration, *Ident_USR;
+ /// ParseScope - Introduces a new scope for parsing. The kind of
+ /// scope is determined by ScopeFlags. Objects of this type should
+ /// be created on the stack to coincide with the position where the
+ /// parser enters the new scope, and this object's constructor will
+ /// create that new scope. Similarly, once the object is destroyed
+ /// the parser will exit the scope.
+ class ParseScope {
+ Parser *Self;
+ ParseScope(const ParseScope &) = delete;
+ void operator=(const ParseScope &) = delete;
- /// C++11 contextual keywords.
- mutable IdentifierInfo *Ident_final;
- mutable IdentifierInfo *Ident_GNU_final;
- mutable IdentifierInfo *Ident_override;
+ public:
+ // ParseScope - Construct a new object to manage a scope in the
+ // parser Self where the new Scope is created with the flags
+ // ScopeFlags, but only when we aren't about to enter a compound statement.
+ ParseScope(Parser *Self, unsigned ScopeFlags, bool EnteredScope = true,
+ bool BeforeCompoundStmt = false)
+ : Self(Self) {
+ if (EnteredScope && !BeforeCompoundStmt)
+ Self->EnterScope(ScopeFlags);
+ else {
+ if (BeforeCompoundStmt)
+ Self->incrementMSManglingNumber();
- // C++2a contextual keywords.
- mutable IdentifierInfo *Ident_import;
- mutable IdentifierInfo *Ident_module;
+ this->Self = nullptr;
+ }
+ }
- // C++ type trait keywords that can be reverted to identifiers and still be
- // used as type traits.
- llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
+ // Exit - Exit the scope associated with this object now, rather
+ // than waiting until the object is destroyed.
+ void Exit() {
+ if (Self) {
+ Self->ExitScope();
+ Self = nullptr;
+ }
+ }
- std::unique_ptr<PragmaHandler> AlignHandler;
- std::unique_ptr<PragmaHandler> GCCVisibilityHandler;
- std::unique_ptr<PragmaHandler> OptionsHandler;
- std::unique_ptr<PragmaHandler> PackHandler;
- std::unique_ptr<PragmaHandler> MSStructHandler;
- std::unique_ptr<PragmaHandler> UnusedHandler;
- std::unique_ptr<PragmaHandler> WeakHandler;
- std::unique_ptr<PragmaHandler> RedefineExtnameHandler;
- std::unique_ptr<PragmaHandler> FPContractHandler;
- std::unique_ptr<PragmaHandler> OpenCLExtensionHandler;
- std::unique_ptr<PragmaHandler> OpenMPHandler;
- std::unique_ptr<PragmaHandler> OpenACCHandler;
- std::unique_ptr<PragmaHandler> PCSectionHandler;
- std::unique_ptr<PragmaHandler> MSCommentHandler;
- std::unique_ptr<PragmaHandler> MSDetectMismatchHandler;
- std::unique_ptr<PragmaHandler> FPEvalMethodHandler;
- std::unique_ptr<PragmaHandler> FloatControlHandler;
- std::unique_ptr<PragmaHandler> MSPointersToMembers;
- std::unique_ptr<PragmaHandler> MSVtorDisp;
- std::unique_ptr<PragmaHandler> MSInitSeg;
- std::unique_ptr<PragmaHandler> MSDataSeg;
- std::unique_ptr<PragmaHandler> MSBSSSeg;
- std::unique_ptr<PragmaHandler> MSConstSeg;
- std::unique_ptr<PragmaHandler> MSCodeSeg;
- std::unique_ptr<PragmaHandler> MSSection;
- std::unique_ptr<PragmaHandler> MSStrictGuardStackCheck;
- std::unique_ptr<PragmaHandler> MSRuntimeChecks;
- std::unique_ptr<PragmaHandler> MSIntrinsic;
- std::unique_ptr<PragmaHandler> MSFunction;
- std::unique_ptr<PragmaHandler> MSOptimize;
- std::unique_ptr<PragmaHandler> MSFenvAccess;
- std::unique_ptr<PragmaHandler> MSAllocText;
- std::unique_ptr<PragmaHandler> CUDAForceHostDeviceHandler;
- std::unique_ptr<PragmaHandler> OptimizeHandler;
- std::unique_ptr<PragmaHandler> LoopHintHandler;
- std::unique_ptr<PragmaHandler> UnrollHintHandler;
- std::unique_ptr<PragmaHandler> NoUnrollHintHandler;
- std::unique_ptr<PragmaHandler> UnrollAndJamHintHandler;
- std::unique_ptr<PragmaHandler> NoUnrollAndJamHintHandler;
- std::unique_ptr<PragmaHandler> FPHandler;
- std::unique_ptr<PragmaHandler> STDCFenvAccessHandler;
- std::unique_ptr<PragmaHandler> STDCFenvRoundHandler;
- std::unique_ptr<PragmaHandler> STDCCXLIMITHandler;
- std::unique_ptr<PragmaHandler> STDCUnknownHandler;
- std::unique_ptr<PragmaHandler> AttributePragmaHandler;
- std::unique_ptr<PragmaHandler> MaxTokensHerePragmaHandler;
- std::unique_ptr<PragmaHandler> MaxTokensTotalPragmaHandler;
- std::unique_ptr<PragmaHandler> RISCVPragmaHandler;
+ ~ParseScope() { Exit(); }
+ };
- std::unique_ptr<CommentHandler> CommentSemaHandler;
+ /// Introduces zero or more scopes for parsing. The scopes will all be exited
+ /// when the object is destroyed.
+ class MultiParseScope {
+ Parser &Self;
+ unsigned NumScopes = 0;
- /// Whether the '>' token acts as an operator or not. This will be
- /// true except when we are parsing an expression within a C++
- /// template argument list, where the '>' closes the template
- /// argument list.
- bool GreaterThanIsOperator;
+ MultiParseScope(const MultiParseScope &) = delete;
- /// ColonIsSacred - When this is false, we aggressively try to recover from
- /// code like "foo : bar" as if it were a typo for "foo :: bar". This is not
- /// safe in case statements and a few other things. This is managed by the
- /// ColonProtectionRAIIObject RAII object.
- bool ColonIsSacred;
+ public:
+ MultiParseScope(Parser &Self) : Self(Self) {}
+ void Enter(unsigned ScopeFlags) {
+ Self.EnterScope(ScopeFlags);
+ ++NumScopes;
+ }
+ void Exit() {
+ while (NumScopes) {
+ Self.ExitScope();
+ --NumScopes;
+ }
+ }
+ ~MultiParseScope() { Exit(); }
+ };
- /// Parsing OpenMP directive mode.
- bool OpenMPDirectiveParsing = false;
+ /// EnterScope - Start a new scope.
+ void EnterScope(unsigned ScopeFlags);
- /// Parsing OpenACC directive mode.
- bool OpenACCDirectiveParsing = false;
+ /// ExitScope - Pop a scope off the scope stack.
+ void ExitScope();
- /// Currently parsing a situation where an OpenACC array section could be
- /// legal, such as a 'var-list'.
- bool AllowOpenACCArraySections = false;
+ //===--------------------------------------------------------------------===//
+ // Diagnostic Emission and Error recovery.
- /// RAII object to set reset OpenACC parsing a context where Array Sections
- /// are allowed.
- class OpenACCArraySectionRAII {
- Parser &P;
+ DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID);
+ DiagnosticBuilder Diag(const Token...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/138511
More information about the cfe-commits
mailing list