23#include "llvm/ADT/ScopeExit.h"
24#include "llvm/ADT/SmallString.h"
25#include "llvm/ADT/StringMap.h"
26#include "llvm/ADT/StringSwitch.h"
35struct DirectiveWithTokens {
40 : Kind(Kind), NumTokens(NumTokens) {}
43enum class CXX20ModuleDirectiveKind {
46 NamedModuleDeclaration,
50static CXX20ModuleDirectiveKind scanFirstCXX20ModuleDirective(StringRef Source);
72 Scanner(StringRef Input,
73 SmallVectorImpl<dependency_directives_scan::Token> &Tokens,
74 DiagnosticsEngine *Diags, SourceLocation InputSourceLoc)
75 : Input(Input), Tokens(Tokens), Diags(Diags),
76 InputSourceLoc(InputSourceLoc), LangOpts(getLangOptsForDepScanning()),
77 TheLexer(InputSourceLoc, LangOpts, Input.begin(), Input.begin(),
80 static LangOptions getLangOptsForDepScanning() {
84 LangOpts.LineComment =
true;
85 LangOpts.RawStringLiterals =
true;
86 LangOpts.AllowLiteralDigitSeparator =
true;
94 bool scan(SmallVectorImpl<Directive> &Directives);
96 friend CXX20ModuleDirectiveKind
97 scanFirstCXX20ModuleDirective(StringRef Source);
102 [[nodiscard]] dependency_directives_scan::Token &
103 lexToken(
const char *&
First,
const char *
const End);
105 [[nodiscard]] dependency_directives_scan::Token &
106 lexIncludeFilename(
const char *&
First,
const char *
const End);
108 void skipLine(
const char *&
First,
const char *
const End);
109 void skipDirective(StringRef Name,
const char *&
First,
const char *
const End);
113 StringRef cleanStringIfNeeded(
const dependency_directives_scan::Token &
Tok);
120 [[nodiscard]] std::optional<StringRef>
121 tryLexIdentifierOrSkipLine(
const char *&
First,
const char *
const End);
124 [[nodiscard]] StringRef lexIdentifier(
const char *&
First,
125 const char *
const End);
132 [[nodiscard]]
bool isNextIdentifierOrSkipLine(StringRef Id,
134 const char *
const End);
142 const char *
const End);
149 [[nodiscard]] std::optional<StringRef>
150 tryLexStringLiteralOrSkipLine(
const char *&
First,
const char *
const End);
152 [[nodiscard]]
bool scanImpl(
const char *
First,
const char *
const End);
153 [[nodiscard]]
bool lexPPLine(
const char *&
First,
const char *
const End);
154 [[nodiscard]]
bool lexAt(
const char *&
First,
const char *
const End);
155 [[nodiscard]]
bool lexModule(
const char *&
First,
const char *
const End);
156 [[nodiscard]]
bool lexDefine(
const char *HashLoc,
const char *&
First,
157 const char *
const End);
158 [[nodiscard]]
bool lexPragma(
const char *&
First,
const char *
const End);
159 [[nodiscard]]
bool lex_Pragma(
const char *&
First,
const char *
const End);
160 [[nodiscard]]
bool lexEndif(
const char *&
First,
const char *
const End);
162 const char *
const End);
163 [[nodiscard]]
bool lexModuleDirectiveBody(
DirectiveKind Kind,
165 const char *
const End);
166 void lexPPDirectiveBody(
const char *&
First,
const char *
const End);
169 Tokens.append(CurDirToks);
170 DirsWithToks.emplace_back(Kind, CurDirToks.size());
172 return DirsWithToks.back();
174 void popDirective() {
175 Tokens.pop_back_n(DirsWithToks.pop_back_val().NumTokens);
178 return DirsWithToks.empty() ?
pp_none : DirsWithToks.back().Kind;
181 unsigned getOffsetAt(
const char *CurPtr)
const {
182 return CurPtr - Input.data();
187 bool reportError(
const char *CurPtr,
unsigned Err);
189 bool ScanningPreprocessedModuleFile =
false;
190 StringMap<char> SplitIds;
192 SmallVectorImpl<dependency_directives_scan::Token> &Tokens;
193 DiagnosticsEngine *Diags;
194 SourceLocation InputSourceLoc;
196 const char *LastTokenPtr =
nullptr;
200 SmallVector<dependency_directives_scan::Token, 32> CurDirToks;
204 SmallVector<DirectiveWithTokens, 64> DirsWithToks;
205 LangOptions LangOpts;
211bool Scanner::reportError(
const char *CurPtr,
unsigned Err) {
214 assert(CurPtr >= Input.data() &&
"invalid buffer ptr");
226 assert(Current >
First);
230 if (Current >
First && *(Current - 1) ==
'\\') {
234 if (EscapeSize > 0) {
237 Current -= (1 + EscapeSize);
249 const char *Current) {
250 assert(
First <= Current);
253 if (*Current !=
'"' ||
First == Current)
259 if (
First == Current ||
264 if (*Current ==
'u' || *Current ==
'U' || *Current ==
'L')
265 return First == Current ||
269 if (*Current !=
'8' ||
First == Current ||
272 return First == Current ||
277 assert(
First[0] ==
'"');
299 while (
Last != End &&
size_t(
Last -
First) < Terminator.size() &&
308 if (
size_t(
Last -
First) < Terminator.size())
318static unsigned isEOL(
const char *
First,
const char *
const End) {
329 const char Terminator = *
First ==
'<' ?
'>' : *
First;
344 const char *FirstAfterBackslashPastSpace =
First;
346 if (
unsigned NLSize =
isEOL(FirstAfterBackslashPastSpace, End)) {
349 First = FirstAfterBackslashPastSpace + NLSize - 1;
362 assert(Len &&
"expected newline");
376 char LastNonWhitespace =
' ';
379 LastNonWhitespace = *
First;
385 if (LastNonWhitespace !=
'\\')
401 if (End -
First < 4) {
415 const char *
const Cur,
416 const char *
const End) {
417 assert(*Cur ==
'\'' &&
"expected quotation character");
425 char Prev = *(Cur - 1);
426 if (Prev ==
'L' || Prev ==
'U' || Prev ==
'u')
428 if (Prev ==
'8' && (Cur - 1 != Start) && *(Cur - 2) ==
'u')
436void Scanner::skipLine(
const char *&
First,
const char *
const End) {
438 assert(
First <= End);
446 const char *Start =
First;
449 char LastNonWhitespace =
' ';
454 LastTokenPtr =
First;
472 LastTokenPtr =
First;
474 LastNonWhitespace = *
First;
479 if (
First[1] ==
'/') {
485 if (
First[1] !=
'*') {
486 LastTokenPtr =
First;
488 LastNonWhitespace = *
First;
502 if (LastNonWhitespace !=
'\\')
507void Scanner::skipDirective(StringRef Name,
const char *&
First,
508 const char *
const End) {
509 if (llvm::StringSwitch<bool>(Name)
510 .Case(
"warning",
true)
516 skipLine(
First, End);
521 assert(
First <= End);
527 if (*
First ==
'\\') {
528 const char *Ptr =
First + 1;
544 if (
First[1] ==
'/') {
559 const char *
const End) {
560 assert(Kind == DirectiveKind::cxx_export_import_decl ||
561 Kind == DirectiveKind::cxx_export_module_decl ||
562 Kind == DirectiveKind::cxx_import_decl ||
563 Kind == DirectiveKind::cxx_module_decl ||
564 Kind == DirectiveKind::decl_at_import);
566 const char *DirectiveLoc = Input.data() + CurDirToks.front().Offset;
570 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
573 CurDirToks.pop_back();
580 diag::err_dep_source_scanner_missing_semi_after_at_import);
581 if (
Tok.
is(tok::semi))
585 bool IsCXXModules =
Kind == DirectiveKind::cxx_export_import_decl ||
586 Kind == DirectiveKind::cxx_export_module_decl ||
587 Kind == DirectiveKind::cxx_import_decl ||
588 Kind == DirectiveKind::cxx_module_decl;
590 lexPPDirectiveBody(
First, End);
595 const auto &
Tok = lexToken(
First, End);
599 return reportError(DirectiveLoc,
600 diag::err_dep_source_scanner_unexpected_tokens_at_import);
603dependency_directives_scan::Token &Scanner::lexToken(
const char *&
First,
604 const char *
const End) {
608 assert(
First <= End);
611 CurDirToks.emplace_back(Offset,
Tok.getLength(),
Tok.getKind(),
613 return CurDirToks.back();
616dependency_directives_scan::Token &
617Scanner::lexIncludeFilename(
const char *&
First,
const char *
const End) {
621 assert(
First <= End);
624 CurDirToks.emplace_back(Offset,
Tok.getLength(),
Tok.getKind(),
626 return CurDirToks.back();
629void Scanner::lexPPDirectiveBody(
const char *&
First,
const char *
const End) {
631 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
638Scanner::cleanStringIfNeeded(
const dependency_directives_scan::Token &
Tok) {
640 if (LLVM_LIKELY(!NeedsCleaning))
643 SmallString<64> Spelling;
649 unsigned SpellingLength = 0;
650 const char *BufPtr = Input.begin() +
Tok.
Offset;
651 const char *AfterIdent = Input.begin() +
Tok.
getEnd();
652 while (BufPtr < AfterIdent) {
654 Spelling[SpellingLength++] = Char;
658 return SplitIds.try_emplace(StringRef(Spelling.begin(), SpellingLength), 0)
662std::optional<StringRef>
663Scanner::tryLexIdentifierOrSkipLine(
const char *&
First,
const char *
const End) {
664 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
665 if (
Tok.
isNot(tok::raw_identifier)) {
666 if (!
Tok.
is(tok::eod))
667 skipLine(
First, End);
671 return cleanStringIfNeeded(
Tok);
674StringRef Scanner::lexIdentifier(
const char *&
First,
const char *
const End) {
675 std::optional<StringRef> Id = tryLexIdentifierOrSkipLine(
First, End);
676 assert(Id &&
"expected identifier token");
680bool Scanner::isNextIdentifierOrSkipLine(StringRef Id,
const char *&
First,
681 const char *
const End) {
682 if (std::optional<StringRef> FoundId =
683 tryLexIdentifierOrSkipLine(
First, End)) {
686 skipLine(
First, End);
692 const char *
const End) {
693 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
696 skipLine(
First, End);
700std::optional<StringRef>
701Scanner::tryLexStringLiteralOrSkipLine(
const char *&
First,
702 const char *
const End) {
703 const dependency_directives_scan::Token &
Tok = lexToken(
First, End);
705 if (!
Tok.
is(tok::eod))
706 skipLine(
First, End);
710 return cleanStringIfNeeded(
Tok);
713bool Scanner::lexAt(
const char *&
First,
const char *
const End) {
717 const dependency_directives_scan::Token &AtTok = lexToken(
First, End);
718 assert(AtTok.
is(tok::at));
721 if (!isNextIdentifierOrSkipLine(
"import",
First, End))
726bool Scanner::lexModule(
const char *&
First,
const char *
const End) {
727 StringRef Id = lexIdentifier(
First, End);
729 if (Id ==
"export") {
731 std::optional<StringRef> NextId = tryLexIdentifierOrSkipLine(
First, End);
738 ScanningPreprocessedModuleFile ?
"__preprocessed_module" :
"module";
740 ScanningPreprocessedModuleFile ?
"__preprocessed_import" :
"import";
742 if (Id !=
Module && Id != Import) {
743 skipLine(
First, End);
756 skipLine(
First, End);
763 skipLine(
First, End);
767 (void)lexToken(
First, End);
768 if (!tryLexIdentifierOrSkipLine(
First, End))
774 if (Id ==
Module && !Export)
776 skipLine(
First, End);
784 skipLine(
First, End);
789 TheLexer.
seek(getOffsetAt(
First),
false);
797 return lexModuleDirectiveBody(Kind,
First, End);
800bool Scanner::lex_Pragma(
const char *&
First,
const char *
const End) {
801 if (!isNextTokenOrSkipLine(tok::l_paren,
First, End))
804 std::optional<StringRef> Str = tryLexStringLiteralOrSkipLine(
First, End);
806 if (!Str || !isNextTokenOrSkipLine(tok::r_paren,
First, End))
809 SmallString<64> Buffer(*Str);
815 SmallVector<dependency_directives_scan::Token> DiscardTokens;
816 const char *Begin = Buffer.c_str();
817 Scanner PragmaScanner{StringRef(Begin, Buffer.size()), DiscardTokens, Diags,
821 if (PragmaScanner.lexPragma(Begin, Buffer.end()))
826 skipLine(
First, End);
830 assert(Begin == Buffer.end());
835bool Scanner::lexPragma(
const char *&
First,
const char *
const End) {
836 std::optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(
First, End);
840 StringRef Id = *FoundId;
841 auto Kind = llvm::StringSwitch<DirectiveKind>(Id)
848 lexPPDirectiveBody(
First, End);
854 skipLine(
First, End);
858 FoundId = tryLexIdentifierOrSkipLine(
First, End);
864 if (Id ==
"system_header") {
865 lexPPDirectiveBody(
First, End);
870 if (Id !=
"module") {
871 skipLine(
First, End);
876 if (!isNextIdentifierOrSkipLine(
"import",
First, End))
880 lexPPDirectiveBody(
First, End);
885bool Scanner::lexEndif(
const char *&
First,
const char *
const End) {
898 skipLine(
First, End);
906 const char *
const End) {
907 lexPPDirectiveBody(
First, End);
927 assert(
First <= End);
930 return Str.starts_with(
938bool Scanner::lexPPLine(
const char *&
First,
const char *
const End) {
939 assert(
First != End);
942 assert(
First <= End);
947 skipLine(
First, End);
948 assert(
First <= End);
952 LastTokenPtr =
First;
956 llvm::scope_exit ScEx1([&]() {
962 bool IsPreprocessedModule =
964 if (*
First ==
'_' && !IsPreprocessedModule) {
965 if (isNextIdentifierOrSkipLine(
"_Pragma",
First, End))
966 return lex_Pragma(
First, End);
973 llvm::scope_exit ScEx2(
977 return lexAt(
First, End);
980 if (*
First ==
'i' || *
First ==
'e' || *
First ==
'm' || IsPreprocessedModule)
981 return lexModule(
First, End);
984 const dependency_directives_scan::Token &HashTok = lexToken(
First, End);
985 if (HashTok.
is(tok::hashhash)) {
989 skipLine(
First, End);
990 assert(
First <= End);
993 assert(HashTok.
is(tok::hash));
996 std::optional<StringRef> FoundId = tryLexIdentifierOrSkipLine(
First, End);
1000 StringRef Id = *FoundId;
1003 return lexPragma(
First, End);
1005 auto Kind = llvm::StringSwitch<DirectiveKind>(Id)
1022 skipDirective(Id,
First, End);
1027 return lexEndif(
First, End);
1035 if (lexIncludeFilename(
First, End).
is(tok::eod)) {
1044 return lexDefault(Kind,
First, End);
1053bool Scanner::scanImpl(
const char *
First,
const char *
const End) {
1055 while (
First != End)
1056 if (lexPPLine(
First, End))
1061bool Scanner::scan(SmallVectorImpl<Directive> &Directives) {
1063 bool Error = scanImpl(Input.begin(), Input.end());
1068 (Tokens.empty() || LastTokenPtr > Input.begin() + Tokens.back().Offset))
1073 ArrayRef<dependency_directives_scan::Token> RemainingTokens = Tokens;
1074 for (
const DirectiveWithTokens &DirWithToks : DirsWithToks) {
1075 assert(RemainingTokens.size() >= DirWithToks.NumTokens);
1076 Directives.emplace_back(DirWithToks.Kind,
1077 RemainingTokens.take_front(DirWithToks.NumTokens));
1078 RemainingTokens = RemainingTokens.drop_front(DirWithToks.NumTokens);
1080 assert(RemainingTokens.empty());
1089 return Scanner(Input, Tokens, Diags, InputSourceLoc).scan(Directives);
1095 llvm::raw_ostream &OS) {
1097 auto needsSpaceSeparator =
1100 if (Prev ==
Tok.Kind)
1101 return !
Tok.isOneOf(tok::l_paren, tok::r_paren, tok::l_square,
1103 if (Prev == tok::raw_identifier &&
1104 Tok.isOneOf(tok::hash, tok::numeric_constant, tok::string_literal,
1105 tok::char_constant, tok::header_name))
1107 if (Prev == tok::r_paren &&
1108 Tok.isOneOf(tok::raw_identifier, tok::hash, tok::string_literal,
1109 tok::char_constant, tok::unknown))
1111 if (Prev == tok::comma &&
1112 Tok.isOneOf(tok::l_paren, tok::string_literal, tok::less))
1119 OS <<
"<TokBeforeEOF>";
1120 std::optional<tok::TokenKind> PrevTokenKind;
1122 if (PrevTokenKind && needsSpaceSeparator(*PrevTokenKind,
Tok))
1124 PrevTokenKind =
Tok.Kind;
1125 OS << Source.slice(
Tok.Offset,
Tok.getEnd());
1131 const char *
const End) {
1132 assert(
First <= End);
1133 while (
First != End) {
1134 if (*
First ==
'#') {
1149static CXX20ModuleDirectiveKind
1150scanFirstCXX20ModuleDirective(StringRef Source) {
1151 const char *
First = Source.begin();
1152 const char *
const End = Source.end();
1155 return CXX20ModuleDirectiveKind::None;
1160 return CXX20ModuleDirectiveKind::None;
1162 llvm::SmallVector<dependency_directives_scan::Token> Tokens;
1163 Scanner S(StringRef(
First, End -
First), Tokens,
nullptr, SourceLocation());
1164 S.TheLexer.setParsingPreprocessorDirective(
true);
1165 if (S.lexModule(
First, End) || S.DirsWithToks.empty())
1166 return CXX20ModuleDirectiveKind::None;
1168 assert(S.DirsWithToks.size() == 1);
1169 const DirectiveWithTokens &
Directive = S.DirsWithToks.front();
1173 return Tokens[1].is(tok::semi)
1174 ? CXX20ModuleDirectiveKind::GlobalModuleFragment
1175 : CXX20ModuleDirectiveKind::NamedModuleDeclaration;
1177 return CXX20ModuleDirectiveKind::NamedModuleDeclaration;
1180 return CXX20ModuleDirectiveKind::ImportDeclaration;
1182 llvm_unreachable(
"unexpected C++20 module directive kind");
1189 return scanFirstCXX20ModuleDirective(Source) !=
1190 CXX20ModuleDirectiveKind::None;
1194 switch (scanFirstCXX20ModuleDirective(Source)) {
1195 case CXX20ModuleDirectiveKind::GlobalModuleFragment:
1197 case CXX20ModuleDirectiveKind::NamedModuleDeclaration:
1199 case CXX20ModuleDirectiveKind::None:
1200 case CXX20ModuleDirectiveKind::ImportDeclaration:
1203 llvm_unreachable(
"unexpected C++20 module directive kind");
1207 const char *
First = Source.begin();
1208 const char *
const End = Source.end();
1216 while (
First != End) {
1217 if (*
First ==
'#') {
1220 }
else if (*
First ==
'e') {
1221 S.TheLexer.
seek(S.getOffsetAt(
First),
true);
1222 StringRef Id = S.lexIdentifier(
First, End);
1223 if (Id ==
"export") {
1224 std::optional<StringRef> NextId =
1225 S.tryLexIdentifierOrSkipLine(
First, End);
1230 if (Id ==
"__preprocessed_module" || Id ==
"__preprocessed_import")
Defines the Diagnostic-related interfaces.
static void skipBlockComment(const char *&First, const char *const End)
static void skipRawString(const char *&First, const char *const End)
static void skipString(const char *&First, const char *const End)
static bool isStartOfRelevantLine(char First)
static bool isStartWithPreprocessedModuleDirective(const char *First, const char *End)
static bool isRawStringLiteral(const char *First, const char *Current)
static void skipUntilMaybeCXX20ModuleDirective(const char *&First, const char *const End)
static void skipOverSpaces(const char *&First, const char *const End)
static unsigned isEOL(const char *First, const char *const End)
static char previousChar(const char *First, const char *&Current)
static void skipToNewlineRaw(const char *&First, const char *const End)
static unsigned skipNewline(const char *&First, const char *End)
static void skipUTF8ByteOrderMark(const char *&First, const char *const End)
static void skipLineComment(const char *&First, const char *const End)
static bool isQuoteCppDigitSeparator(const char *const Start, const char *const Cur, const char *const End)
This is the interface for scanning header and source files to get the minimum necessary preprocessor ...
static unsigned skipWhitespace(unsigned Idx, StringRef Str, unsigned Length)
Skip over whitespace in the string, starting at the given index.
VerifyDiagnosticConsumer::Directive Directive
Concrete class used by the front-end to report problems and issues.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
bool LexFromRawLexer(Token &Result)
LexFromRawLexer - Lex a token from a designated raw lexer (one with no associated preprocessor object...
static unsigned getEscapedNewLineSize(const char *P)
getEscapedNewLineSize - Return the size of the specified escaped newline, or 0 if it is not an escape...
void seek(unsigned Offset, bool IsAtStartOfLine)
Set the lexer's buffer pointer to Offset.
unsigned getCurrentBufferOffset()
Returns the current lexing offset.
static SizedChar getCharAndSizeNoWarn(const char *Ptr, const LangOptions &LangOpts)
getCharAndSizeNoWarn - Like the getCharAndSize method, but does not ever emit a warning.
void setParsingPreprocessorDirective(bool f)
Inform the lexer whether or not we are currently lexing a preprocessor directive.
void LexIncludeFilename(Token &FilenameTok)
Lex a token, producing a header-name token if possible.
Encodes a location in the source.
SourceLocation getLocWithOffset(IntTy Offset) const
Return a source location with the specified offset from this SourceLocation.
DirectiveKind
Represents the kind of preprocessor directive or a module declaration that is tracked by the scanner ...
@ tokens_present_before_eof
Indicates that there are tokens present between the last scanned directive and eof.
@ pp_pragma_system_header
@ pp_pragma_include_alias
bool isStringLiteral(TokenKind K)
Return true if this is a C or C++ string-literal (or C++11 user-defined-string-literal) token.
const char * getPPKeywordSpelling(PPKeywordKind Kind) LLVM_READNONE
Returns the spelling of preprocessor keywords, such as "else".
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
Top level wrappers for InstallAPI frontend operations.
LLVM_READONLY bool isVerticalWhitespace(unsigned char c)
Returns true if this character is vertical ASCII whitespace: '\n', '\r'.
LLVM_READONLY bool isAsciiIdentifierContinue(unsigned char c)
void printDependencyDirectivesAsSource(StringRef Source, ArrayRef< dependency_directives_scan::Directive > Directives, llvm::raw_ostream &OS)
Print the previously scanned dependency directives as minimized source text.
bool scanInputForCXX20ModulesUsage(StringRef Source)
Scan an input source buffer for C++20 named module usage.
bool isPreprocessedModuleFile(StringRef Source)
Scan an input source buffer, and check whether the input source is a preprocessed output.
LLVM_READONLY bool isHorizontalWhitespace(unsigned char c)
Returns true if this character is horizontal ASCII whitespace: ' ', '\t', '\f', '\v'.
bool scanSourceForDependencyDirectives(StringRef Input, SmallVectorImpl< dependency_directives_scan::Token > &Tokens, SmallVectorImpl< dependency_directives_scan::Directive > &Directives, DiagnosticsEngine *Diags=nullptr, SourceLocation InputSourceLoc=SourceLocation())
Scan the input for the preprocessor directives that might have an effect on the dependencies for a co...
@ Module
Module linkage, which indicates that the entity can be referred to from other translation units withi...
@ Default
Set to the current date and time.
ModuleUnitKind
Describes how a source input starts a C++20 module unit.
@ HasGlobalModuleFragment
@ NamedModuleWithoutGlobalModuleFragment
LLVM_READONLY bool isWhitespace(unsigned char c)
Return true if this character is horizontal or vertical ASCII whitespace: ' ', '\t',...
LLVM_READONLY bool isPreprocessingNumberBody(unsigned char c)
Return true if this is the body character of a C preprocessing number, which is [a-zA-Z0-9_.
void prepare_PragmaString(SmallVectorImpl< char > &StrVal)
Destringize a _Pragma("") string according to C11 6.10.9.1: "The string literal is destringized by de...
ModuleUnitKind scanInputForCXX20ModuleUnit(StringRef Source)
Scan an input source buffer to determine whether it starts a C++20 module unit, and whether that modu...
@ None
The alignment was not explicit in code.
Diagnostic wrappers for TextAPI types for error reporting.
Represents a directive that's lexed as part of the dependency directives scanning.
DirectiveKind Kind
The kind of token.
Token lexed as part of dependency directive scanning.
bool isNot(tok::TokenKind K) const
unsigned Offset
Offset into the original source input.
bool is(tok::TokenKind K) const
bool isOneOf(Ts... Ks) const