//===--- PPDirectives.cpp - Directive Handling for Preprocessor -----------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// Implements # directive processing for the Preprocessor. /// //===----------------------------------------------------------------------===// #include "clang/Basic/CharInfo.h" #include "clang/Basic/DirectoryEntry.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/ModuleMap.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Pragma.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "clang/Lex/VariadicMacroSupport.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/AlignOf.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include "llvm/Support/SaveAndRestore.h" #include <algorithm> #include <cassert> #include <cstring> #include <new> #include <optional> #include <string> #include <utility> usingnamespaceclang; //===----------------------------------------------------------------------===// // Utility Methods for Preprocessor Directive Handling. //===----------------------------------------------------------------------===// MacroInfo *Preprocessor::AllocateMacroInfo(SourceLocation L) { … } DefMacroDirective *Preprocessor::AllocateDefMacroDirective(MacroInfo *MI, SourceLocation Loc) { … } UndefMacroDirective * Preprocessor::AllocateUndefMacroDirective(SourceLocation UndefLoc) { … } VisibilityMacroDirective * Preprocessor::AllocateVisibilityMacroDirective(SourceLocation Loc, bool isPublic) { … } /// Read and discard all tokens remaining on the current line until /// the tok::eod token is found. SourceRange Preprocessor::DiscardUntilEndOfDirective(Token &Tmp) { … } /// Enumerates possible cases of #define/#undef a reserved identifier. enum MacroDiag { … }; /// Enumerates possible %select values for the pp_err_elif_after_else and /// pp_err_elif_without_if diagnostics. enum PPElifDiag { … }; static bool isFeatureTestMacro(StringRef MacroName) { … } static bool isLanguageDefinedBuiltin(const SourceManager &SourceMgr, const MacroInfo *MI, const StringRef MacroName) { … } static MacroDiag shouldWarnOnMacroDef(Preprocessor &PP, IdentifierInfo *II) { … } static MacroDiag shouldWarnOnMacroUndef(Preprocessor &PP, IdentifierInfo *II) { … } // Return true if we want to issue a diagnostic by default if we // encounter this name in a #include with the wrong case. For now, // this includes the standard C and C++ headers, Posix headers, // and Boost headers. Improper case for these #includes is a // potential portability issue. static bool warnByDefaultOnWrongCase(StringRef Include) { … } /// Find a similar string in `Candidates`. /// /// \param LHS a string for a similar string in `Candidates` /// /// \param Candidates the candidates to find a similar string. /// /// \returns a similar string if exists. If no similar string exists, /// returns std::nullopt. static std::optional<StringRef> findSimilarStr(StringRef LHS, const std::vector<StringRef> &Candidates) { … } bool Preprocessor::CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef, bool *ShadowFlag) { … } /// Lex and validate a macro name, which occurs after a /// \#define or \#undef. /// /// This sets the token kind to eod and discards the rest of the macro line if /// the macro name is invalid. /// /// \param MacroNameTok Token that is expected to be a macro name. /// \param isDefineUndef Context in which macro is used. /// \param ShadowFlag Points to a flag that is set if macro shadows a keyword. void Preprocessor::ReadMacroName(Token &MacroNameTok, MacroUse isDefineUndef, bool *ShadowFlag) { … } /// Ensure that the next token is a tok::eod token. /// /// If not, emit a diagnostic and consume up until the eod. If EnableMacros is /// true, then we consider macros that expand to zero tokens as being ok. /// /// Returns the location of the end of the directive. SourceLocation Preprocessor::CheckEndOfDirective(const char *DirType, bool EnableMacros) { … } void Preprocessor::SuggestTypoedDirective(const Token &Tok, StringRef Directive) const { … } /// SkipExcludedConditionalBlock - 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 /// FoundNonSkipPortion is true, then we have already emitted code for part of /// this \#if directive, so \#else/\#elif blocks should never be entered. /// If ElseOk is true, then \#else directives are ok, if not, then we have /// already seen one so a \#else directive is a duplicate. When this returns, /// the caller can lex the first valid token. void Preprocessor::SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, SourceLocation IfTokenLoc, bool FoundNonSkipPortion, bool FoundElse, SourceLocation ElseLoc) { … } Module *Preprocessor::getModuleForLocation(SourceLocation Loc, bool AllowTextual) { … } OptionalFileEntryRef Preprocessor::getHeaderToIncludeForDiagnostics(SourceLocation IncLoc, SourceLocation Loc) { … } OptionalFileEntryRef Preprocessor::LookupFile( SourceLocation FilenameLoc, StringRef Filename, bool isAngled, ConstSearchDirIterator FromDir, const FileEntry *FromFile, ConstSearchDirIterator *CurDirArg, SmallVectorImpl<char> *SearchPath, SmallVectorImpl<char> *RelativePath, ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, bool *IsFrameworkFound, bool SkipCache, bool OpenFile, bool CacheFailures) { … } OptionalFileEntryRef Preprocessor::LookupEmbedFile(StringRef Filename, bool isAngled, bool OpenFile, const FileEntry *LookupFromFile) { … } //===----------------------------------------------------------------------===// // Preprocessor Directive Handling. //===----------------------------------------------------------------------===// class Preprocessor::ResetMacroExpansionHelper { … }; /// Process a directive while looking for the through header or a #pragma /// hdrstop. The following directives are handled: /// #include (to check if it is the through header) /// #define (to warn about macros that don't match the PCH) /// #pragma (to check for pragma hdrstop). /// All other directives are completely discarded. void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result, SourceLocation HashLoc) { … } /// HandleDirective - This callback is invoked when the lexer sees a # token /// at the start of a line. This consumes the directive, modifies the /// lexer/preprocessor state, and advances the lexer(s) so that the next token /// read is the correct one. void Preprocessor::HandleDirective(Token &Result) { … } /// GetLineValue - Convert a numeric token into an unsigned value, emitting /// Diagnostic DiagID if it is invalid, and returning the value in Val. static bool GetLineValue(Token &DigitTok, unsigned &Val, unsigned DiagID, Preprocessor &PP, bool IsGNULineDirective=false) { … } /// Handle a \#line directive: C99 6.10.4. /// /// The two acceptable forms are: /// \verbatim /// # line digit-sequence /// # line digit-sequence "s-char-sequence" /// \endverbatim void Preprocessor::HandleLineDirective() { … } /// ReadLineMarkerFlags - Parse and validate any flags at the end of a GNU line /// marker directive. static bool ReadLineMarkerFlags(bool &IsFileEntry, bool &IsFileExit, SrcMgr::CharacteristicKind &FileKind, Preprocessor &PP) { … } /// HandleDigitDirective - Handle a GNU line marker directive, whose syntax is /// one of the following forms: /// /// # 42 /// # 42 "file" ('1' | '2')? /// # 42 "file" ('1' | '2')? '3' '4'? /// void Preprocessor::HandleDigitDirective(Token &DigitTok) { … } /// HandleUserDiagnosticDirective - Handle a #warning or #error directive. /// void Preprocessor::HandleUserDiagnosticDirective(Token &Tok, bool isWarning) { … } /// HandleIdentSCCSDirective - Handle a #ident/#sccs directive. /// void Preprocessor::HandleIdentSCCSDirective(Token &Tok) { … } /// Handle a #public directive. void Preprocessor::HandleMacroPublicDirective(Token &Tok) { … } /// Handle a #private directive. void Preprocessor::HandleMacroPrivateDirective() { … } //===----------------------------------------------------------------------===// // Preprocessor Include Directive Handling. //===----------------------------------------------------------------------===// /// GetIncludeFilenameSpelling - Turn the specified lexer token into a fully /// checked and spelled filename, e.g. as an operand of \#include. This returns /// true if the input filename was in <>'s or false if it were in ""'s. The /// caller is expected to provide a buffer that is large enough to hold the /// spelling of the filename, but is also expected to handle the case when /// this method decides to use a different buffer. bool Preprocessor::GetIncludeFilenameSpelling(SourceLocation Loc, StringRef &Buffer) { … } /// Push a token onto the token stream containing an annotation. void Preprocessor::EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, void *AnnotationVal) { … } /// Produce a diagnostic informing the user that a #include or similar /// was implicitly treated as a module import. static void diagnoseAutoModuleImport( Preprocessor &PP, SourceLocation HashLoc, Token &IncludeTok, ArrayRef<std::pair<IdentifierInfo *, SourceLocation>> Path, SourceLocation PathEnd) { … } // Given a vector of path components and a string containing the real // path to the file, build a properly-cased replacement in the vector, // and return true if the replacement should be suggested. static bool trySimplifyPath(SmallVectorImpl<StringRef> &Components, StringRef RealPathName, llvm::sys::path::Style Separator) { … } bool Preprocessor::checkModuleIsAvailable(const LangOptions &LangOpts, const TargetInfo &TargetInfo, const Module &M, DiagnosticsEngine &Diags) { … } std::pair<ConstSearchDirIterator, const FileEntry *> Preprocessor::getIncludeNextStart(const Token &IncludeNextTok) const { … } /// HandleIncludeDirective - The "\#include" tokens have just been read, read /// the file to be included from the lexer, then include it! This is a common /// routine with functionality shared between \#include, \#include_next and /// \#import. LookupFrom is set when this is a \#include_next directive, it /// specifies the file to start searching from. void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, Token &IncludeTok, ConstSearchDirIterator LookupFrom, const FileEntry *LookupFromFile) { … } OptionalFileEntryRef Preprocessor::LookupHeaderIncludeOrImport( ConstSearchDirIterator *CurDir, StringRef &Filename, SourceLocation FilenameLoc, CharSourceRange FilenameRange, const Token &FilenameTok, bool &IsFrameworkFound, bool IsImportDecl, bool &IsMapped, ConstSearchDirIterator LookupFrom, const FileEntry *LookupFromFile, StringRef &LookupFilename, SmallVectorImpl<char> &RelativePath, SmallVectorImpl<char> &SearchPath, ModuleMap::KnownHeader &SuggestedModule, bool isAngled) { … } /// Handle either a #include-like directive or an import declaration that names /// a header file. /// /// \param HashLoc The location of the '#' token for an include, or /// SourceLocation() for an import declaration. /// \param IncludeTok The include / include_next / import token. /// \param FilenameTok The header-name token. /// \param EndLoc The location at which any imported macros become visible. /// \param LookupFrom For #include_next, the starting directory for the /// directory lookup. /// \param LookupFromFile For #include_next, the starting file for the directory /// lookup. Preprocessor::ImportAction Preprocessor::HandleHeaderIncludeOrImport( SourceLocation HashLoc, Token &IncludeTok, Token &FilenameTok, SourceLocation EndLoc, ConstSearchDirIterator LookupFrom, const FileEntry *LookupFromFile) { … } /// HandleIncludeNextDirective - Implements \#include_next. /// void Preprocessor::HandleIncludeNextDirective(SourceLocation HashLoc, Token &IncludeNextTok) { … } /// HandleMicrosoftImportDirective - Implements \#import for Microsoft Mode void Preprocessor::HandleMicrosoftImportDirective(Token &Tok) { … } /// HandleImportDirective - Implements \#import. /// void Preprocessor::HandleImportDirective(SourceLocation HashLoc, Token &ImportTok) { … } /// HandleIncludeMacrosDirective - The -imacros command line option turns into a /// pseudo directive in the predefines buffer. This handles it by sucking all /// tokens through the preprocessor and discarding them (only keeping the side /// effects on the preprocessor). void Preprocessor::HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &IncludeMacrosTok) { … } //===----------------------------------------------------------------------===// // Preprocessor Macro Directive Handling. //===----------------------------------------------------------------------===// /// ReadMacroParameterList - The ( starting a parameter list of a macro /// definition has just been read. Lex the rest of the parameters and the /// closing ), updating MI with what we learn. Return true if an error occurs /// parsing the param list. bool Preprocessor::ReadMacroParameterList(MacroInfo *MI, Token &Tok) { … } static bool isConfigurationPattern(Token &MacroName, MacroInfo *MI, const LangOptions &LOptions) { … } // ReadOptionalMacroParameterListAndBody - This consumes all (i.e. the // entire line) of the macro's tokens and adds them to MacroInfo, and while // doing so performs certain validity checks including (but not limited to): // - # (stringization) is followed by a macro parameter // // Returns a nullptr if an invalid sequence of tokens is encountered or returns // a pointer to a MacroInfo object. MacroInfo *Preprocessor::ReadOptionalMacroParameterListAndBody( const Token &MacroNameTok, const bool ImmediatelyAfterHeaderGuard) { … } static bool isObjCProtectedMacro(const IdentifierInfo *II) { … } /// HandleDefineDirective - Implements \#define. This consumes the entire macro /// line then lets the caller lex the next real token. void Preprocessor::HandleDefineDirective( Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) { … } /// HandleUndefDirective - Implements \#undef. /// void Preprocessor::HandleUndefDirective() { … } //===----------------------------------------------------------------------===// // Preprocessor Conditional Directive Handling. //===----------------------------------------------------------------------===// /// HandleIfdefDirective - Implements the \#ifdef/\#ifndef directive. isIfndef /// is true when this is a \#ifndef directive. ReadAnyTokensBeforeDirective is /// true if any tokens have been returned or pp-directives activated before this /// \#ifndef has been lexed. /// void Preprocessor::HandleIfdefDirective(Token &Result, const Token &HashToken, bool isIfndef, bool ReadAnyTokensBeforeDirective) { … } /// HandleIfDirective - Implements the \#if directive. /// void Preprocessor::HandleIfDirective(Token &IfToken, const Token &HashToken, bool ReadAnyTokensBeforeDirective) { … } /// HandleEndifDirective - Implements the \#endif directive. /// void Preprocessor::HandleEndifDirective(Token &EndifToken) { … } /// HandleElseDirective - Implements the \#else directive. /// void Preprocessor::HandleElseDirective(Token &Result, const Token &HashToken) { … } /// Implements the \#elif, \#elifdef, and \#elifndef directives. void Preprocessor::HandleElifFamilyDirective(Token &ElifToken, const Token &HashToken, tok::PPKeywordKind Kind) { … } std::optional<LexEmbedParametersResult> Preprocessor::LexEmbedParameters(Token &CurTok, bool ForHasEmbed) { … } void Preprocessor::HandleEmbedDirectiveImpl( SourceLocation HashLoc, const LexEmbedParametersResult &Params, StringRef BinaryContents) { … } void Preprocessor::HandleEmbedDirective(SourceLocation HashLoc, Token &EmbedTok, const FileEntry *LookupFromFile) { … }