aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h')
-rw-r--r--contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h706
1 files changed, 618 insertions, 88 deletions
diff --git a/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h b/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h
index fe2327f0a480..b0a8ec0fec5e 100644
--- a/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h
+++ b/contrib/llvm-project/clang/include/clang/Lex/Preprocessor.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_LEX_PREPROCESSOR_H
#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
@@ -22,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"
@@ -51,6 +50,7 @@
#include <cstdint>
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include <utility>
#include <vector>
@@ -66,7 +66,6 @@ namespace clang {
class CodeCompletionHandler;
class CommentHandler;
class DirectoryEntry;
-class DirectoryLookup;
class EmptylineHandler;
class ExternalPreprocessorSource;
class FileEntry;
@@ -133,7 +132,7 @@ class Preprocessor {
llvm::unique_function<void(const clang::Token &)> OnToken;
std::shared_ptr<PreprocessorOptions> PPOpts;
DiagnosticsEngine *Diags;
- LangOptions &LangOpts;
+ const LangOptions &LangOpts;
const TargetInfo *Target = nullptr;
const TargetInfo *AuxTarget = nullptr;
FileManager &FileMgr;
@@ -164,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
@@ -178,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;
@@ -260,8 +277,7 @@ 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).
+ /// True to avoid tearing down the lexer etc on EOF
bool IncrementalProcessing = false;
public:
@@ -292,14 +308,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.
@@ -309,7 +328,7 @@ private:
AfterImportSeq = -3,
};
- ImportSeq(State S) : S(S) {}
+ StdCXXImportSeq(State S) : S(S) {}
/// Saw any kind of open bracket.
void handleOpenBracket() {
@@ -364,6 +383,7 @@ private:
bool atTopLevel() { return S <= 0; }
bool afterImportSeq() { return S == AfterImportSeq; }
+ bool afterTopLevelSeq() { return S == AfterTopLevelTokenSeq; }
private:
State S;
@@ -374,7 +394,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 ';'.
@@ -388,6 +607,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;
@@ -401,7 +628,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
@@ -449,6 +676,8 @@ public:
ElseLoc(ElseLoc) {}
};
+ using IncludedFilesSet = llvm::DenseSet<const FileEntry *>;
+
private:
friend class ASTReader;
friend class MacroArgs;
@@ -486,11 +715,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;
@@ -503,7 +732,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.
@@ -514,7 +743,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.
///
@@ -522,12 +751,8 @@ private:
std::unique_ptr<TokenLexer> CurTokenLexer;
/// The kind of lexer we're currently working with.
- enum CurLexerKind {
- CLK_Lexer,
- CLK_TokenLexer,
- CLK_CachingLexer,
- CLK_LexAfterModuleImport
- } CurLexerKind = CLK_Lexer;
+ typedef bool (*LexerCallback)(Preprocessor &, Token &);
+ LexerCallback CurLexerCallback = &CLK_Lexer;
/// If the current lexer is for a submodule that is being built, this
/// is that submodule.
@@ -537,21 +762,21 @@ private:
/// \#included, and macros currently being expanded from, not counting
/// CurLexer/CurTokenLexer.
struct IncludeStackInfo {
- enum CurLexerKind CurLexerKind;
+ LexerCallback CurLexerCallback;
Module *TheSubmodule;
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.
- IncludeStackInfo(enum CurLexerKind CurLexerKind, Module *TheSubmodule,
+ IncludeStackInfo(LexerCallback CurLexerCallback, Module *TheSubmodule,
std::unique_ptr<Lexer> &&TheLexer,
PreprocessorLexer *ThePPLexer,
std::unique_ptr<TokenLexer> &&TheTokenLexer,
- const DirectoryLookup *TheDirLookup)
- : CurLexerKind(std::move(CurLexerKind)),
+ ConstSearchDirIterator TheDirLookup)
+ : CurLexerCallback(std::move(CurLexerCallback)),
TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)),
ThePPLexer(std::move(ThePPLexer)),
TheTokenLexer(std::move(TheTokenLexer)),
@@ -665,7 +890,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,
@@ -689,7 +914,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,
@@ -764,6 +989,13 @@ private:
/// in a submodule.
SubmoduleState *CurSubmoduleState;
+ /// 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;
@@ -786,6 +1018,42 @@ private:
using WarnUnusedMacroLocsTy = llvm::SmallDenseSet<SourceLocation, 32>;
WarnUnusedMacroLocsTy WarnUnusedMacroLocs;
+ /// This is a pair of an optional message and source location used for pragmas
+ /// that annotate macros like pragma clang restrict_expansion and pragma clang
+ /// deprecated. This pair stores the optional message and the location of the
+ /// annotation pragma for use producing diagnostics and notes.
+ using MsgLocationPair = std::pair<std::string, SourceLocation>;
+
+ struct MacroAnnotationInfo {
+ SourceLocation Location;
+ std::string Message;
+ };
+
+ struct MacroAnnotations {
+ 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)},
+ std::nullopt, std::nullopt};
+ }
+
+ static MacroAnnotations makeRestrictExpansion(SourceLocation Loc,
+ std::string Msg) {
+ return MacroAnnotations{
+ std::nullopt, MacroAnnotationInfo{Loc, std::move(Msg)}, std::nullopt};
+ }
+
+ static MacroAnnotations makeFinal(SourceLocation Loc) {
+ return MacroAnnotations{std::nullopt, std::nullopt, Loc};
+ }
+ };
+
+ /// Warning information for macro annotations.
+ llvm::DenseMap<const IdentifierInfo *, MacroAnnotations> AnnotationInfos;
+
/// A "freelist" of MacroArg objects that can be
/// reused for quick allocation.
MacroArgs *MacroArgCache = nullptr;
@@ -872,21 +1140,25 @@ 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;
public:
Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts,
- DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM,
- HeaderSearch &Headers, ModuleLoader &TheModuleLoader,
+ DiagnosticsEngine &diags, const LangOptions &LangOpts,
+ SourceManager &SM, HeaderSearch &Headers,
+ ModuleLoader &TheModuleLoader,
IdentifierInfoLookup *IILookup = nullptr,
bool OwnsHeaderSearch = false,
TranslationUnitKind TUKind = TU_Complete);
@@ -1161,7 +1433,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.
@@ -1187,19 +1459,55 @@ 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(FileEntryRef File) {
+ HeaderInfo.getFileInfo(File);
+ return IncludedFiles.insert(File).second;
+ }
+
+ /// Return true if this header has already been included.
+ bool alreadyIncluded(FileEntryRef File) const {
+ HeaderInfo.getFileInfo(File);
+ return IncludedFiles.count(File);
+ }
+
+ /// Get the set of included files.
+ IncludedFilesSet &getIncludedFiles() { return IncludedFiles; }
+ const IncludedFilesSet &getIncludedFiles() const { return IncludedFiles; }
+
/// Return the name of the macro defined before \p Loc that has
/// spelling \p Tokens. If there are multiple macros with same spelling,
/// return the last one defined.
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.
@@ -1330,8 +1638,8 @@ 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,
- SourceLocation Loc);
+ bool EnterSourceFile(FileID FID, ConstSearchDirIterator Dir,
+ SourceLocation Loc, bool IsFirstIncludeOfFile = true);
/// Add a Macro to the top of the include stack and start lexing
/// tokens from it instead of the current buffer.
@@ -1409,6 +1717,9 @@ public:
/// Lex the next token for this preprocessor.
void Lex(Token &Result);
+ /// Lex all tokens for this preprocessor until (and excluding) end of file.
+ void LexTokensUntilEOF(std::vector<Token> *Tokens = nullptr);
+
/// Lex a token, forming a header-name token if possible.
bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true);
@@ -1585,7 +1896,7 @@ public:
/// Determine whether it's possible for a future call to Lex to produce an
/// annotation token created by a previous call to EnterAnnotationToken.
bool mightHavePendingAnnotationTokens() {
- return CurLexerKind != CLK_Lexer;
+ return CurLexerCallback != CLK_Lexer;
}
/// Update the current token to represent the provided
@@ -1622,8 +1933,8 @@ public:
/// (1-based).
///
/// \returns true if an error occurred, false otherwise.
- bool SetCodeCompletionPoint(const FileEntry *File,
- unsigned Line, unsigned Column);
+ bool SetCodeCompletionPoint(FileEntryRef File, unsigned Line,
+ unsigned Column);
/// Determine if we are performing code completion.
bool isCodeCompletionEnabled() const { return CodeCompletionFile != nullptr; }
@@ -1684,11 +1995,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.
///
@@ -1953,8 +2277,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.
@@ -1990,9 +2313,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);
@@ -2009,22 +2397,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;
@@ -2043,8 +2425,9 @@ private:
friend void TokenLexer::ExpandFunctionArguments();
void PushIncludeMacroStack() {
- assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer");
- IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule,
+ assert(CurLexerCallback != CLK_CachingLexer &&
+ "cannot push a caching lexer");
+ IncludeMacroStack.emplace_back(CurLexerCallback, CurLexerSubmodule,
std::move(CurLexer), CurPPLexer,
std::move(CurTokenLexer), CurDirLookup);
CurPPLexer = nullptr;
@@ -2056,7 +2439,7 @@ private:
CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer);
CurDirLookup = IncludeMacroStack.back().TheDirLookup;
CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule;
- CurLexerKind = IncludeMacroStack.back().CurLexerKind;
+ CurLexerCallback = IncludeMacroStack.back().CurLexerCallback;
IncludeMacroStack.pop_back();
}
@@ -2107,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
@@ -2139,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();
@@ -2186,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) {
@@ -2250,6 +2654,7 @@ private:
None,
ModuleBegin,
ModuleImport,
+ HeaderUnitImport,
SkippedModuleImport,
Failure,
} Kind;
@@ -2262,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);
@@ -2291,13 +2696,13 @@ public:
/// \c false if the module appears to be usable.
static bool checkModuleIsAvailable(const LangOptions &LangOpts,
const TargetInfo &TargetInfo,
- DiagnosticsEngine &Diags, Module *M);
+ const Module &M, DiagnosticsEngine &Diags);
// Module inclusion testing.
/// 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
@@ -2313,8 +2718,8 @@ public:
/// \return A file that can be #included to provide the desired effect. Null
/// if no such file could be determined or if a #include is not
/// appropriate (eg, if a module should be imported instead).
- const FileEntry *getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
- SourceLocation MLoc);
+ OptionalFileEntryRef getHeaderToIncludeForDiagnostics(SourceLocation IncLoc,
+ SourceLocation MLoc);
bool isRecordingPreamble() const {
return PreambleConditionalStack.isRecording();
@@ -2332,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;
}
@@ -2364,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);
@@ -2388,14 +2791,141 @@ public:
/// warnings.
void markMacroAsUsed(MacroInfo *MI);
+ void addMacroDeprecationMsg(const IdentifierInfo *II, std::string Msg,
+ SourceLocation AnnotationLoc) {
+ auto Annotations = AnnotationInfos.find(II);
+ if (Annotations == AnnotationInfos.end())
+ AnnotationInfos.insert(std::make_pair(
+ II,
+ MacroAnnotations::makeDeprecation(AnnotationLoc, std::move(Msg))));
+ else
+ Annotations->second.DeprecationInfo =
+ MacroAnnotationInfo{AnnotationLoc, std::move(Msg)};
+ }
+
+ void addRestrictExpansionMsg(const IdentifierInfo *II, std::string Msg,
+ SourceLocation AnnotationLoc) {
+ auto Annotations = AnnotationInfos.find(II);
+ if (Annotations == AnnotationInfos.end())
+ AnnotationInfos.insert(
+ std::make_pair(II, MacroAnnotations::makeRestrictExpansion(
+ AnnotationLoc, std::move(Msg))));
+ else
+ Annotations->second.RestrictExpansionInfo =
+ MacroAnnotationInfo{AnnotationLoc, std::move(Msg)};
+ }
+
+ void addFinalLoc(const IdentifierInfo *II, SourceLocation AnnotationLoc) {
+ auto Annotations = AnnotationInfos.find(II);
+ if (Annotations == AnnotationInfos.end())
+ AnnotationInfos.insert(
+ std::make_pair(II, MacroAnnotations::makeFinal(AnnotationLoc)));
+ else
+ Annotations->second.FinalAnnotationLoc = AnnotationLoc;
+ }
+
+ const MacroAnnotations &getMacroAnnotations(const IdentifierInfo *II) const {
+ return AnnotationInfos.find(II)->second;
+ }
+
+ void emitMacroExpansionWarnings(const Token &Identifier,
+ bool IsIfnDef = false) const {
+ IdentifierInfo *Info = Identifier.getIdentifierInfo();
+ if (Info->isDeprecatedMacro())
+ emitMacroDeprecationWarning(Identifier);
+
+ if (Info->isRestrictExpansion() &&
+ !SourceMgr.isInMainFile(Identifier.getLocation()))
+ emitRestrictExpansionWarning(Identifier);
+
+ if (!IsIfnDef) {
+ if (Info->getName() == "INFINITY" && getLangOpts().NoHonorInfs)
+ emitRestrictInfNaNWarning(Identifier, 0);
+ if (Info->getName() == "NAN" && getLangOpts().NoHonorNaNs)
+ emitRestrictInfNaNWarning(Identifier, 1);
+ }
+ }
+
+ 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:
- Optional<unsigned>
- getSkippedRangeForExcludedConditionalBlock(SourceLocation HashLoc);
+ void emitMacroDeprecationWarning(const Token &Identifier) const;
+ void emitRestrictExpansionWarning(const Token &Identifier) const;
+ void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const;
+ void emitRestrictInfNaNWarning(const Token &Identifier,
+ unsigned DiagSelection) const;
+
+ /// 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;
+
+ /// 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;
- /// Contains the currently active skipped range mappings for skipping excluded
- /// conditional directives.
- ExcludedPreprocessorDirectiveSkipMapping
- *ExcludedConditionalDirectiveSkipMappings;
+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);
+
+private:
+ /// Helper functions to forward lexing to the actual lexer. They all share the
+ /// same signature.
+ static bool CLK_Lexer(Preprocessor &P, Token &Result) {
+ return P.CurLexer->Lex(Result);
+ }
+ static bool CLK_TokenLexer(Preprocessor &P, Token &Result) {
+ return P.CurTokenLexer->Lex(Result);
+ }
+ static bool CLK_CachingLexer(Preprocessor &P, Token &Result) {
+ P.CachingLex(Result);
+ return true;
+ }
+ static bool CLK_DependencyDirectivesLexer(Preprocessor &P, Token &Result) {
+ return P.CurLexer->LexDependencyDirectiveToken(Result);
+ }
+ static bool CLK_LexAfterModuleImport(Preprocessor &P, Token &Result) {
+ return P.LexAfterModuleImport(Result);
+ }
};
/// Abstract base class that describes a handler that will receive