diff options
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h')
-rw-r--r-- | contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h | 543 |
1 files changed, 467 insertions, 76 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h index e567f6391531..9efe439bc5f2 100644 --- a/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h +++ b/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h @@ -23,20 +23,18 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" +#include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PPCallbacks.h" -#include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h" #include "clang/Lex/Token.h" #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/FunctionExtras.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerUnion.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -52,6 +50,7 @@ #include <cstdint> #include <map> #include <memory> +#include <optional> #include <string> #include <utility> #include <vector> @@ -67,7 +66,6 @@ namespace clang { class CodeCompletionHandler; class CommentHandler; class DirectoryEntry; -class DirectoryLookup; class EmptylineHandler; class ExternalPreprocessorSource; class FileEntry; @@ -165,6 +163,7 @@ class Preprocessor { IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_extension; // __has_extension IdentifierInfo *Ident__has_builtin; // __has_builtin + IdentifierInfo *Ident__has_constexpr_builtin; // __has_constexpr_builtin IdentifierInfo *Ident__has_attribute; // __has_attribute IdentifierInfo *Ident__has_include; // __has_include IdentifierInfo *Ident__has_include_next; // __has_include_next @@ -179,12 +178,29 @@ class Preprocessor { IdentifierInfo *Ident__is_target_vendor; // __is_target_vendor IdentifierInfo *Ident__is_target_os; // __is_target_os IdentifierInfo *Ident__is_target_environment; // __is_target_environment + IdentifierInfo *Ident__is_target_variant_os; + IdentifierInfo *Ident__is_target_variant_environment; + IdentifierInfo *Ident__FLT_EVAL_METHOD__; // __FLT_EVAL_METHOD // Weak, only valid (and set) while InMacroArgs is true. Token* ArgMacro; SourceLocation DATELoc, TIMELoc; + // FEM_UnsetOnCommandLine means that an explicit evaluation method was + // not specified on the command line. The target is queried to set the + // default evaluation method. + LangOptions::FPEvalMethodKind CurrentFPEvalMethod = + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + + // The most recent pragma location where the floating point evaluation + // method was modified. This is used to determine whether the + // 'pragma clang fp eval_method' was used whithin the current scope. + SourceLocation LastFPEvalPragmaLocation; + + LangOptions::FPEvalMethodKind TUFPEvalMethod = + LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; + // Next __COUNTER__ value, starts at 0. unsigned CounterValue = 0; @@ -261,10 +277,6 @@ class Preprocessor { /// Empty line handler. EmptylineHandler *Emptyline = nullptr; - /// True if we want to ignore EOF token and continue later on (thus - /// avoid tearing the Lexer and etc. down). - bool IncrementalProcessing = false; - public: /// The kind of translation unit we are processing. const TranslationUnitKind TUKind; @@ -293,14 +305,17 @@ private: /// lexed, if any. SourceLocation ModuleImportLoc; - /// The module import path that we're currently processing. - SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> ModuleImportPath; + /// The import path for named module that we're currently processing. + SmallVector<std::pair<IdentifierInfo *, SourceLocation>, 2> NamedModuleImportPath; + + /// Whether the import is an `@import` or a standard c++ modules import. + bool IsAtImport = false; /// Whether the last token we lexed was an '@'. bool LastTokenWasAt = false; /// A position within a C++20 import-seq. - class ImportSeq { + class StdCXXImportSeq { public: enum State : int { // Positive values represent a number of unclosed brackets. @@ -310,7 +325,7 @@ private: AfterImportSeq = -3, }; - ImportSeq(State S) : S(S) {} + StdCXXImportSeq(State S) : S(S) {} /// Saw any kind of open bracket. void handleOpenBracket() { @@ -365,6 +380,7 @@ private: bool atTopLevel() { return S <= 0; } bool afterImportSeq() { return S == AfterImportSeq; } + bool afterTopLevelSeq() { return S == AfterTopLevelTokenSeq; } private: State S; @@ -375,7 +391,206 @@ private: }; /// Our current position within a C++20 import-seq. - ImportSeq ImportSeqState = ImportSeq::AfterTopLevelTokenSeq; + StdCXXImportSeq StdCXXImportSeqState = StdCXXImportSeq::AfterTopLevelTokenSeq; + + /// Track whether we are in a Global Module Fragment + class TrackGMF { + public: + enum GMFState : int { + GMFActive = 1, + MaybeGMF = 0, + BeforeGMFIntroducer = -1, + GMFAbsentOrEnded = -2, + }; + + TrackGMF(GMFState S) : S(S) {} + + /// Saw a semicolon. + void handleSemi() { + // If it is immediately after the first instance of the module keyword, + // then that introduces the GMF. + if (S == MaybeGMF) + S = GMFActive; + } + + /// Saw an 'export' identifier. + void handleExport() { + // The presence of an 'export' keyword always ends or excludes a GMF. + S = GMFAbsentOrEnded; + } + + /// Saw an 'import' identifier. + void handleImport(bool AfterTopLevelTokenSeq) { + // If we see this before any 'module' kw, then we have no GMF. + if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer) + S = GMFAbsentOrEnded; + } + + /// Saw a 'module' identifier. + void handleModule(bool AfterTopLevelTokenSeq) { + // This was the first module identifier and not preceded by any token + // that would exclude a GMF. It could begin a GMF, but only if directly + // followed by a semicolon. + if (AfterTopLevelTokenSeq && S == BeforeGMFIntroducer) + S = MaybeGMF; + else + S = GMFAbsentOrEnded; + } + + /// Saw any other token. + void handleMisc() { + // We saw something other than ; after the 'module' kw, so not a GMF. + if (S == MaybeGMF) + S = GMFAbsentOrEnded; + } + + bool inGMF() { return S == GMFActive; } + + private: + /// Track the transitions into and out of a Global Module Fragment, + /// if one is present. + GMFState S; + }; + + TrackGMF TrackGMFState = TrackGMF::BeforeGMFIntroducer; + + /// Track the status of the c++20 module decl. + /// + /// module-declaration: + /// 'export'[opt] 'module' module-name module-partition[opt] + /// attribute-specifier-seq[opt] ';' + /// + /// module-name: + /// module-name-qualifier[opt] identifier + /// + /// module-partition: + /// ':' module-name-qualifier[opt] identifier + /// + /// module-name-qualifier: + /// identifier '.' + /// module-name-qualifier identifier '.' + /// + /// Transition state: + /// + /// NotAModuleDecl --- export ---> FoundExport + /// NotAModuleDecl --- module ---> ImplementationCandidate + /// FoundExport --- module ---> InterfaceCandidate + /// ImplementationCandidate --- Identifier ---> ImplementationCandidate + /// ImplementationCandidate --- period ---> ImplementationCandidate + /// ImplementationCandidate --- colon ---> ImplementationCandidate + /// InterfaceCandidate --- Identifier ---> InterfaceCandidate + /// InterfaceCandidate --- period ---> InterfaceCandidate + /// InterfaceCandidate --- colon ---> InterfaceCandidate + /// ImplementationCandidate --- Semi ---> NamedModuleImplementation + /// NamedModuleInterface --- Semi ---> NamedModuleInterface + /// NamedModuleImplementation --- Anything ---> NamedModuleImplementation + /// NamedModuleInterface --- Anything ---> NamedModuleInterface + /// + /// FIXME: We haven't handle attribute-specifier-seq here. It may not be bad + /// soon since we don't support any module attributes yet. + class ModuleDeclSeq { + enum ModuleDeclState : int { + NotAModuleDecl, + FoundExport, + InterfaceCandidate, + ImplementationCandidate, + NamedModuleInterface, + NamedModuleImplementation, + }; + + public: + ModuleDeclSeq() = default; + + void handleExport() { + if (State == NotAModuleDecl) + State = FoundExport; + else if (!isNamedModule()) + reset(); + } + + void handleModule() { + if (State == FoundExport) + State = InterfaceCandidate; + else if (State == NotAModuleDecl) + State = ImplementationCandidate; + else if (!isNamedModule()) + reset(); + } + + void handleIdentifier(IdentifierInfo *Identifier) { + if (isModuleCandidate() && Identifier) + Name += Identifier->getName().str(); + else if (!isNamedModule()) + reset(); + } + + void handleColon() { + if (isModuleCandidate()) + Name += ":"; + else if (!isNamedModule()) + reset(); + } + + void handlePeriod() { + if (isModuleCandidate()) + Name += "."; + else if (!isNamedModule()) + reset(); + } + + void handleSemi() { + if (!Name.empty() && isModuleCandidate()) { + if (State == InterfaceCandidate) + State = NamedModuleInterface; + else if (State == ImplementationCandidate) + State = NamedModuleImplementation; + else + llvm_unreachable("Unimaged ModuleDeclState."); + } else if (!isNamedModule()) + reset(); + } + + void handleMisc() { + if (!isNamedModule()) + reset(); + } + + bool isModuleCandidate() const { + return State == InterfaceCandidate || State == ImplementationCandidate; + } + + bool isNamedModule() const { + return State == NamedModuleInterface || + State == NamedModuleImplementation; + } + + bool isNamedInterface() const { return State == NamedModuleInterface; } + + bool isImplementationUnit() const { + return State == NamedModuleImplementation && !getName().contains(':'); + } + + StringRef getName() const { + assert(isNamedModule() && "Can't get name from a non named module"); + return Name; + } + + StringRef getPrimaryName() const { + assert(isNamedModule() && "Can't get name from a non named module"); + return getName().split(':').first; + } + + void reset() { + Name.clear(); + State = NotAModuleDecl; + } + + private: + ModuleDeclState State = NotAModuleDecl; + std::string Name; + }; + + ModuleDeclSeq ModuleDeclState; /// Whether the module import expects an identifier next. Otherwise, /// it expects a '.' or ';'. @@ -389,6 +604,14 @@ private: /// \#pragma clang assume_nonnull begin. SourceLocation PragmaAssumeNonNullLoc; + /// Set only for preambles which end with an active + /// \#pragma clang assume_nonnull begin. + /// + /// When the preamble is loaded into the main file, + /// `PragmaAssumeNonNullLoc` will be set to this to + /// replay the unterminated assume_nonnull. + SourceLocation PreambleRecordedPragmaAssumeNonNullLoc; + /// True if we hit the code-completion point. bool CodeCompletionReached = false; @@ -402,7 +625,7 @@ private: /// The directory that the main file should be considered to occupy, /// if it does not correspond to a real file (as happens when building a /// module). - const DirectoryEntry *MainFileDir = nullptr; + OptionalDirectoryEntryRef MainFileDir; /// The number of bytes that we will initially skip when entering the /// main file, along with a flag that indicates whether skipping this number @@ -489,11 +712,11 @@ private: bool hasRecordedPreamble() const { return !ConditionalStack.empty(); } - bool reachedEOFWhileSkipping() const { return SkipInfo.hasValue(); } + bool reachedEOFWhileSkipping() const { return SkipInfo.has_value(); } void clearSkipInfo() { SkipInfo.reset(); } - llvm::Optional<PreambleSkipInfo> SkipInfo; + std::optional<PreambleSkipInfo> SkipInfo; private: SmallVector<PPConditionalInfo, 4> ConditionalStack; @@ -506,7 +729,7 @@ private: /// Only one of CurLexer, or CurTokenLexer will be non-null. std::unique_ptr<Lexer> CurLexer; - /// The current top of the stack what we're lexing from + /// The current top of the stack that we're lexing from /// if not expanding a macro. /// /// This is an alias for CurLexer. @@ -517,7 +740,7 @@ private: /// /// This allows us to implement \#include_next and find directory-specific /// properties. - const DirectoryLookup *CurDirLookup = nullptr; + ConstSearchDirIterator CurDirLookup = nullptr; /// The current macro we are expanding, if we are expanding a macro. /// @@ -529,6 +752,7 @@ private: CLK_Lexer, CLK_TokenLexer, CLK_CachingLexer, + CLK_DependencyDirectivesLexer, CLK_LexAfterModuleImport } CurLexerKind = CLK_Lexer; @@ -545,7 +769,7 @@ private: std::unique_ptr<Lexer> TheLexer; PreprocessorLexer *ThePPLexer; std::unique_ptr<TokenLexer> TheTokenLexer; - const DirectoryLookup *TheDirLookup; + ConstSearchDirIterator TheDirLookup; // The following constructors are completely useless copies of the default // versions, only needed to pacify MSVC. @@ -553,7 +777,7 @@ private: std::unique_ptr<Lexer> &&TheLexer, PreprocessorLexer *ThePPLexer, std::unique_ptr<TokenLexer> &&TheTokenLexer, - const DirectoryLookup *TheDirLookup) + ConstSearchDirIterator TheDirLookup) : CurLexerKind(std::move(CurLexerKind)), TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)), ThePPLexer(std::move(ThePPLexer)), @@ -668,7 +892,7 @@ private: getActiveModuleMacros(Preprocessor &PP, const IdentifierInfo *II) const { if (auto *Info = getModuleInfo(PP, II)) return Info->ActiveModuleMacros; - return None; + return std::nullopt; } MacroDirective::DefInfo findDirectiveAtLoc(SourceLocation Loc, @@ -692,7 +916,7 @@ private: ArrayRef<ModuleMacro*> getOverriddenMacros() const { if (auto *Info = State.dyn_cast<ModuleMacroInfo*>()) return Info->OverriddenMacros; - return None; + return std::nullopt; } void setOverriddenMacros(Preprocessor &PP, @@ -770,6 +994,10 @@ private: /// The files that have been included. IncludedFilesSet IncludedFiles; + /// The set of top-level modules that affected preprocessing, but were not + /// imported. + llvm::SmallSetVector<Module *, 2> AffectingClangModules; + /// The set of known macros exported from modules. llvm::FoldingSet<ModuleMacro> ModuleMacros; @@ -804,24 +1032,24 @@ private: }; struct MacroAnnotations { - llvm::Optional<MacroAnnotationInfo> DeprecationInfo; - llvm::Optional<MacroAnnotationInfo> RestrictExpansionInfo; - llvm::Optional<SourceLocation> FinalAnnotationLoc; + std::optional<MacroAnnotationInfo> DeprecationInfo; + std::optional<MacroAnnotationInfo> RestrictExpansionInfo; + std::optional<SourceLocation> FinalAnnotationLoc; static MacroAnnotations makeDeprecation(SourceLocation Loc, std::string Msg) { return MacroAnnotations{MacroAnnotationInfo{Loc, std::move(Msg)}, - llvm::None, llvm::None}; + std::nullopt, std::nullopt}; } static MacroAnnotations makeRestrictExpansion(SourceLocation Loc, std::string Msg) { return MacroAnnotations{ - llvm::None, MacroAnnotationInfo{Loc, std::move(Msg)}, llvm::None}; + std::nullopt, MacroAnnotationInfo{Loc, std::move(Msg)}, std::nullopt}; } static MacroAnnotations makeFinal(SourceLocation Loc) { - return MacroAnnotations{llvm::None, llvm::None, Loc}; + return MacroAnnotations{std::nullopt, std::nullopt, Loc}; } }; @@ -914,14 +1142,17 @@ private: /// invoked (at which point the last position is popped). std::vector<CachedTokensTy::size_type> BacktrackPositions; - struct MacroInfoChain { - MacroInfo MI; - MacroInfoChain *Next; - }; + /// True if \p Preprocessor::SkipExcludedConditionalBlock() is running. + /// This is used to guard against calling this function recursively. + /// + /// See comments at the use-site for more context about why it is needed. + bool SkippingExcludedConditionalBlock = false; - /// MacroInfos are managed as a chain for easy disposal. This is the head - /// of that list. - MacroInfoChain *MIChainHead = nullptr; + /// Keeps track of skipped range mappings that were recorded while skipping + /// excluded conditional directives. It maps the source buffer pointer at + /// the beginning of a skipped block, to the number of bytes that should be + /// skipped. + llvm::DenseMap<const char *, unsigned> RecordedSkippedRanges; void updateOutOfDateIdentifier(IdentifierInfo &II) const; @@ -1203,7 +1434,7 @@ public: auto I = LeafModuleMacros.find(II); if (I != LeafModuleMacros.end()) return I->second; - return None; + return std::nullopt; } /// Get the list of submodules that we're currently building. @@ -1229,6 +1460,23 @@ public: /// \} + /// Mark the given clang module as affecting the current clang module or translation unit. + void markClangModuleAsAffecting(Module *M) { + assert(M->isModuleMapModule()); + if (!BuildingSubmoduleStack.empty()) { + if (M != BuildingSubmoduleStack.back().M) + BuildingSubmoduleStack.back().M->AffectingClangModules.insert(M); + } else { + AffectingClangModules.insert(M); + } + } + + /// Get the set of top-level clang modules that affected preprocessing, but were not + /// imported. + const llvm::SmallSetVector<Module *, 2> &getAffectingClangModules() const { + return AffectingClangModules; + } + /// Mark the file as included. /// Returns true if this is the first time the file was included. bool markIncluded(const FileEntry *File) { @@ -1238,6 +1486,7 @@ public: /// Return true if this header has already been included. bool alreadyIncluded(const FileEntry *File) const { + HeaderInfo.getFileInfo(File); return IncludedFiles.count(File); } @@ -1251,13 +1500,15 @@ public: StringRef getLastMacroWithSpelling(SourceLocation Loc, ArrayRef<TokenValue> Tokens) const; + /// Get the predefines for this processor. + /// Used by some third-party tools to inspect and add predefines (see + /// https://github.com/llvm/llvm-project/issues/57483). const std::string &getPredefines() const { return Predefines; } /// Set the predefines for this Preprocessor. /// /// These predefines are automatically injected when parsing the main file. - void setPredefines(const char *P) { Predefines = P; } - void setPredefines(StringRef P) { Predefines = std::string(P); } + void setPredefines(std::string P) { Predefines = std::move(P); } /// Return information about the specified preprocessor /// identifier token. @@ -1388,7 +1639,7 @@ public: /// start lexing tokens from it instead of the current buffer. /// /// Emits a diagnostic, doesn't enter the file, and returns true on error. - bool EnterSourceFile(FileID FID, const DirectoryLookup *Dir, + bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir, SourceLocation Loc, bool IsFirstIncludeOfFile = true); /// Add a Macro to the top of the include stack and start lexing @@ -1659,11 +1910,14 @@ public: void recomputeCurLexerKind(); /// Returns true if incremental processing is enabled - bool isIncrementalProcessingEnabled() const { return IncrementalProcessing; } + bool isIncrementalProcessingEnabled() const { + return getLangOpts().IncrementalExtensions; + } /// Enables the incremental processing void enableIncrementalProcessing(bool value = true) { - IncrementalProcessing = value; + // FIXME: Drop this interface. + const_cast<LangOptions &>(getLangOpts()).IncrementalExtensions = value; } /// Specify the point at which code-completion will be performed. @@ -1742,11 +1996,24 @@ public: PragmaAssumeNonNullLoc = Loc; } + /// Get the location of the recorded unterminated \#pragma clang + /// assume_nonnull begin in the preamble, if one exists. + /// + /// Returns an invalid location if the premable did not end with + /// such a pragma active or if there is no recorded preamble. + SourceLocation getPreambleRecordedPragmaAssumeNonNullLoc() const { + return PreambleRecordedPragmaAssumeNonNullLoc; + } + + /// Record the location of the unterminated \#pragma clang + /// assume_nonnull begin in the preamble. + void setPreambleRecordedPragmaAssumeNonNullLoc(SourceLocation Loc) { + PreambleRecordedPragmaAssumeNonNullLoc = Loc; + } + /// Set the directory in which the main file should be considered /// to have been found, if it is not a real file. - void setMainFileDir(const DirectoryEntry *Dir) { - MainFileDir = Dir; - } + void setMainFileDir(DirectoryEntryRef Dir) { MainFileDir = Dir; } /// Instruct the preprocessor to skip part of the main source file. /// @@ -2011,8 +2278,7 @@ public: /// This either returns the EOF token and returns true, or /// pops a level off the include stack and returns false, at which point the /// client should call lex again. - bool HandleEndOfFile(Token &Result, SourceLocation Loc, - bool isEndOfMacro = false); + bool HandleEndOfFile(Token &Result, bool isEndOfMacro = false); /// Callback invoked when the current TokenLexer hits the end of its /// token stream. @@ -2048,9 +2314,74 @@ public: unsigned getCounterValue() const { return CounterValue; } void setCounterValue(unsigned V) { CounterValue = V; } + LangOptions::FPEvalMethodKind getCurrentFPEvalMethod() const { + assert(CurrentFPEvalMethod != LangOptions::FEM_UnsetOnCommandLine && + "FPEvalMethod should be set either from command line or from the " + "target info"); + return CurrentFPEvalMethod; + } + + LangOptions::FPEvalMethodKind getTUFPEvalMethod() const { + return TUFPEvalMethod; + } + + SourceLocation getLastFPEvalPragmaLocation() const { + return LastFPEvalPragmaLocation; + } + + void setCurrentFPEvalMethod(SourceLocation PragmaLoc, + LangOptions::FPEvalMethodKind Val) { + assert(Val != LangOptions::FEM_UnsetOnCommandLine && + "FPEvalMethod should never be set to FEM_UnsetOnCommandLine"); + // This is the location of the '#pragma float_control" where the + // execution state is modifed. + LastFPEvalPragmaLocation = PragmaLoc; + CurrentFPEvalMethod = Val; + TUFPEvalMethod = Val; + } + + void setTUFPEvalMethod(LangOptions::FPEvalMethodKind Val) { + assert(Val != LangOptions::FEM_UnsetOnCommandLine && + "TUPEvalMethod should never be set to FEM_UnsetOnCommandLine"); + TUFPEvalMethod = Val; + } + /// Retrieves the module that we're currently building, if any. Module *getCurrentModule(); + /// Retrieves the module whose implementation we're current compiling, if any. + Module *getCurrentModuleImplementation(); + + /// If we are preprocessing a named module. + bool isInNamedModule() const { return ModuleDeclState.isNamedModule(); } + + /// If we are proprocessing a named interface unit. + /// Note that a module implementation partition is not considered as an + /// named interface unit here although it is importable + /// to ease the parsing. + bool isInNamedInterfaceUnit() const { + return ModuleDeclState.isNamedInterface(); + } + + /// Get the named module name we're preprocessing. + /// Requires we're preprocessing a named module. + StringRef getNamedModuleName() const { return ModuleDeclState.getName(); } + + /// If we are implementing an implementation module unit. + /// Note that the module implementation partition is not considered as an + /// implementation unit. + bool isInImplementationUnit() const { + return ModuleDeclState.isImplementationUnit(); + } + + /// If we're importing a standard C++20 Named Modules. + bool isInImportingCXXNamedModules() const { + // NamedModuleImportPath will be non-empty only if we're importing + // Standard C++ named modules. + return !NamedModuleImportPath.empty() && getLangOpts().CPlusPlusModules && + !IsAtImport; + } + /// Allocate a new MacroInfo object with the provided SourceLocation. MacroInfo *AllocateMacroInfo(SourceLocation L); @@ -2067,22 +2398,16 @@ public: /// Given a "foo" or \<foo> reference, look up the indicated file. /// - /// Returns None on failure. \p isAngled indicates whether the file + /// Returns std::nullopt on failure. \p isAngled indicates whether the file /// reference is for system \#include's or not (i.e. using <> instead of ""). - Optional<FileEntryRef> + OptionalFileEntryRef LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, - const DirectoryLookup *FromDir, const FileEntry *FromFile, - const DirectoryLookup **CurDir, SmallVectorImpl<char> *SearchPath, + ConstSearchDirIterator FromDir, const FileEntry *FromFile, + ConstSearchDirIterator *CurDir, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, - bool *IsFrameworkFound, bool SkipCache = false); - - /// Get the DirectoryLookup structure used to find the current - /// FileEntry, if CurLexer is non-null and if applicable. - /// - /// This allows us to implement \#include_next and find directory-specific - /// properties. - const DirectoryLookup *GetCurDirLookup() { return CurDirLookup; } + bool *IsFrameworkFound, bool SkipCache = false, + bool OpenFile = true, bool CacheFailures = true); /// Return true if we're in the top-level file, not in a \#include. bool isInPrimaryFile() const; @@ -2165,6 +2490,13 @@ private: /// Return true if an error occurs parsing the arg list. bool ReadMacroParameterList(MacroInfo *MI, Token& LastTok); + /// Provide a suggestion for a typoed directive. If there is no typo, then + /// just skip suggesting. + /// + /// \param Tok - Token that represents the directive + /// \param Directive - String reference for the directive name + void SuggestTypoedDirective(const Token &Tok, StringRef Directive) const; + /// We just read a \#if or related directive and decided that the /// subsequent tokens are in the \#if'd out portion of the /// file. Lex the rest of the file, until we see an \#endif. If \p @@ -2197,6 +2529,20 @@ private: /// If the expression is equivalent to "!defined(X)" return X in IfNDefMacro. DirectiveEvalResult EvaluateDirectiveExpression(IdentifierInfo *&IfNDefMacro); + /// Process a '__has_include("path")' expression. + /// + /// Returns true if successful. + bool EvaluateHasInclude(Token &Tok, IdentifierInfo *II); + + /// Process '__has_include_next("path")' expression. + /// + /// Returns true if successful. + bool EvaluateHasIncludeNext(Token &Tok, IdentifierInfo *II); + + /// Get the directory and file from which to start \#include_next lookup. + std::pair<ConstSearchDirIterator, const FileEntry *> + getIncludeNextStart(const Token &IncludeNextTok) const; + /// Install the standard preprocessor pragmas: /// \#pragma GCC poison/system_header/dependency and \#pragma once. void RegisterBuiltinPragmas(); @@ -2244,7 +2590,7 @@ private: /// Add a lexer to the top of the include stack and /// start lexing tokens from it instead of the current buffer. - void EnterSourceFileWithLexer(Lexer *TheLexer, const DirectoryLookup *Dir); + void EnterSourceFileWithLexer(Lexer *TheLexer, ConstSearchDirIterator Dir); /// Set the FileID for the preprocessor predefines. void setPredefinesFileID(FileID FID) { @@ -2308,6 +2654,7 @@ private: None, ModuleBegin, ModuleImport, + HeaderUnitImport, SkippedModuleImport, Failure, } Kind; @@ -2320,23 +2667,23 @@ private: } }; - Optional<FileEntryRef> LookupHeaderIncludeOrImport( - const DirectoryLookup **CurDir, StringRef &Filename, + OptionalFileEntryRef LookupHeaderIncludeOrImport( + ConstSearchDirIterator *CurDir, StringRef &Filename, SourceLocation FilenameLoc, CharSourceRange FilenameRange, const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl, - bool &IsMapped, const DirectoryLookup *LookupFrom, + bool &IsMapped, ConstSearchDirIterator LookupFrom, const FileEntry *LookupFromFile, StringRef &LookupFilename, SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath, ModuleMap::KnownHeader &SuggestedModule, bool isAngled); // File inclusion. void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok, - const DirectoryLookup *LookupFrom = nullptr, + ConstSearchDirIterator LookupFrom = nullptr, const FileEntry *LookupFromFile = nullptr); ImportAction HandleHeaderIncludeOrImport(SourceLocation HashLoc, Token &IncludeTok, Token &FilenameTok, SourceLocation EndLoc, - const DirectoryLookup *LookupFrom = nullptr, + ConstSearchDirIterator LookupFrom = nullptr, const FileEntry *LookupFromFile = nullptr); void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); @@ -2355,7 +2702,7 @@ public: /// Find the module that owns the source or header file that /// \p Loc points to. If the location is in a file that was included /// into a module, or is outside any module, returns nullptr. - Module *getModuleForLocation(SourceLocation Loc); + Module *getModuleForLocation(SourceLocation Loc, bool AllowTextual); /// We want to produce a diagnostic at location IncLoc concerning an /// unreachable effect at location MLoc (eg, where a desired entity was @@ -2390,14 +2737,14 @@ public: PreambleConditionalStack.setStack(s); } - void setReplayablePreambleConditionalStack(ArrayRef<PPConditionalInfo> s, - llvm::Optional<PreambleSkipInfo> SkipInfo) { + void setReplayablePreambleConditionalStack( + ArrayRef<PPConditionalInfo> s, std::optional<PreambleSkipInfo> SkipInfo) { PreambleConditionalStack.startReplaying(); PreambleConditionalStack.setStack(s); PreambleConditionalStack.SkipInfo = SkipInfo; } - llvm::Optional<PreambleSkipInfo> getPreambleSkipInfo() const { + std::optional<PreambleSkipInfo> getPreambleSkipInfo() const { return PreambleConditionalStack.SkipInfo; } @@ -2422,14 +2769,12 @@ private: // Pragmas. void HandlePragmaDirective(PragmaIntroducer Introducer); - void ResolvePragmaIncludeInstead(SourceLocation Location) const; public: void HandlePragmaOnce(Token &OnceTok); void HandlePragmaMark(Token &MarkTok); void HandlePragmaPoison(); void HandlePragmaSystemHeader(Token &SysHeaderTok); - void HandlePragmaIncludeInstead(Token &Tok); void HandlePragmaDependency(Token &DependencyTok); void HandlePragmaPushMacro(Token &Tok); void HandlePragmaPopMacro(Token &Tok); @@ -2492,18 +2837,64 @@ public: emitRestrictExpansionWarning(Identifier); } + static void processPathForFileMacro(SmallVectorImpl<char> &Path, + const LangOptions &LangOpts, + const TargetInfo &TI); + + static void processPathToFileName(SmallVectorImpl<char> &FileName, + const PresumedLoc &PLoc, + const LangOptions &LangOpts, + const TargetInfo &TI); + private: void emitMacroDeprecationWarning(const Token &Identifier) const; void emitRestrictExpansionWarning(const Token &Identifier) const; void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const; - Optional<unsigned> - getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc); + /// This boolean state keeps track if the current scanned token (by this PP) + /// is in an "-Wunsafe-buffer-usage" opt-out region. Assuming PP scans a + /// translation unit in a linear order. + bool InSafeBufferOptOutRegion = false; - /// Contains the currently active skipped range mappings for skipping excluded - /// conditional directives. - ExcludedPreprocessorDirectiveSkipMapping - *ExcludedConditionalDirectiveSkipMappings; + /// Hold the start location of the current "-Wunsafe-buffer-usage" opt-out + /// region if PP is currently in such a region. Hold undefined value + /// otherwise. + SourceLocation CurrentSafeBufferOptOutStart; // It is used to report the start location of an never-closed region. + + // An ordered sequence of "-Wunsafe-buffer-usage" opt-out regions in one + // translation unit. Each region is represented by a pair of start and end + // locations. A region is "open" if its' start and end locations are + // identical. + SmallVector<std::pair<SourceLocation, SourceLocation>, 8> SafeBufferOptOutMap; + +public: + /// \return true iff the given `Loc` is in a "-Wunsafe-buffer-usage" opt-out + /// region. This `Loc` must be a source location that has been pre-processed. + bool isSafeBufferOptOut(const SourceManager&SourceMgr, const SourceLocation &Loc) const; + + /// Alter the state of whether this PP currently is in a + /// "-Wunsafe-buffer-usage" opt-out region. + /// + /// \param isEnter: true if this PP is entering a region; otherwise, this PP + /// is exiting a region + /// \param Loc: the location of the entry or exit of a + /// region + /// \return true iff it is INVALID to enter or exit a region, i.e., + /// attempt to enter a region before exiting a previous region, or exiting a + /// region that PP is not currently in. + bool enterOrExitSafeBufferOptOutRegion(bool isEnter, + const SourceLocation &Loc); + + /// \return true iff this PP is currently in a "-Wunsafe-buffer-usage" + /// opt-out region + bool isPPInSafeBufferOptOutRegion(); + + /// \param StartLoc: output argument. It will be set to the start location of + /// the current "-Wunsafe-buffer-usage" opt-out region iff this function + /// returns true. + /// \return true iff this PP is currently in a "-Wunsafe-buffer-usage" + /// opt-out region + bool isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc); }; /// Abstract base class that describes a handler that will receive |