//===- Pragma.cpp - Pragma registration and handling ----------------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file implements the PragmaHandler/PragmaTable interfaces and implements // pragma related methods of the Preprocessor class. // //===----------------------------------------------------------------------===// #include "clang/Lex/Pragma.h" #include "clang/Basic/CLWarnings.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TokenKinds.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorLexer.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "clang/Lex/TokenLexer.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Timer.h" #include <algorithm> #include <cassert> #include <cstddef> #include <cstdint> #include <limits> #include <optional> #include <string> #include <utility> #include <vector> usingnamespaceclang; // Out-of-line destructor to provide a home for the class. PragmaHandler::~PragmaHandler() = default; //===----------------------------------------------------------------------===// // EmptyPragmaHandler Implementation. //===----------------------------------------------------------------------===// EmptyPragmaHandler::EmptyPragmaHandler(StringRef Name) : … { … } void EmptyPragmaHandler::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &FirstToken) { … } //===----------------------------------------------------------------------===// // PragmaNamespace Implementation. //===----------------------------------------------------------------------===// /// FindHandler - Check to see if there is already a handler for the /// specified name. If not, return the handler for the null identifier if it /// exists, otherwise return null. If IgnoreNull is true (the default) then /// the null handler isn't returned on failure to match. PragmaHandler *PragmaNamespace::FindHandler(StringRef Name, bool IgnoreNull) const { … } void PragmaNamespace::AddPragma(PragmaHandler *Handler) { … } void PragmaNamespace::RemovePragmaHandler(PragmaHandler *Handler) { … } void PragmaNamespace::HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) { … } //===----------------------------------------------------------------------===// // Preprocessor Pragma Directive Handling. //===----------------------------------------------------------------------===// namespace { // TokenCollector provides the option to collect tokens that were "read" // and return them to the stream to be read later. // Currently used when reading _Pragma/__pragma directives. struct TokenCollector { … }; } // namespace /// HandlePragmaDirective - The "\#pragma" directive has been parsed. Lex the /// rest of the pragma, passing it to the registered pragma handlers. void Preprocessor::HandlePragmaDirective(PragmaIntroducer Introducer) { … } /// Handle_Pragma - Read a _Pragma directive, slice it up, process it, then /// return the first token after the directive. The _Pragma token has just /// been read into 'Tok'. void Preprocessor::Handle_Pragma(Token &Tok) { … } void clang::prepare_PragmaString(SmallVectorImpl<char> &StrVal) { … } /// HandleMicrosoft__pragma - Like Handle_Pragma except the pragma text /// is not enclosed within a string literal. void Preprocessor::HandleMicrosoft__pragma(Token &Tok) { … } /// HandlePragmaOnce - Handle \#pragma once. OnceTok is the 'once'. void Preprocessor::HandlePragmaOnce(Token &OnceTok) { … } void Preprocessor::HandlePragmaMark(Token &MarkTok) { … } /// HandlePragmaPoison - Handle \#pragma GCC poison. PoisonTok is the 'poison'. void Preprocessor::HandlePragmaPoison() { … } /// HandlePragmaSystemHeader - Implement \#pragma GCC system_header. We know /// that the whole directive has been parsed. void Preprocessor::HandlePragmaSystemHeader(Token &SysHeaderTok) { … } /// HandlePragmaDependency - Handle \#pragma GCC dependency "foo" blah. void Preprocessor::HandlePragmaDependency(Token &DependencyTok) { … } /// ParsePragmaPushOrPopMacro - Handle parsing of pragma push_macro/pop_macro. /// Return the IdentifierInfo* associated with the macro to push or pop. IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { … } /// Handle \#pragma push_macro. /// /// The syntax is: /// \code /// #pragma push_macro("macro") /// \endcode void Preprocessor::HandlePragmaPushMacro(Token &PushMacroTok) { … } /// Handle \#pragma pop_macro. /// /// The syntax is: /// \code /// #pragma pop_macro("macro") /// \endcode void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { … } void Preprocessor::HandlePragmaIncludeAlias(Token &Tok) { … } // Lex a component of a module name: either an identifier or a string literal; // for components that can be expressed both ways, the two forms are equivalent. static bool LexModuleNameComponent( Preprocessor &PP, Token &Tok, std::pair<IdentifierInfo *, SourceLocation> &ModuleNameComponent, bool First) { … } static bool LexModuleName( Preprocessor &PP, Token &Tok, llvm::SmallVectorImpl<std::pair<IdentifierInfo *, SourceLocation>> &ModuleName) { … } void Preprocessor::HandlePragmaModuleBuild(Token &Tok) { … } void Preprocessor::HandlePragmaHdrstop(Token &Tok) { … } /// AddPragmaHandler - Add the specified pragma handler to the preprocessor. /// If 'Namespace' is non-null, then it is a token required to exist on the /// pragma line before the pragma string starts, e.g. "STDC" or "GCC". void Preprocessor::AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler) { … } /// RemovePragmaHandler - Remove the specific pragma handler from the /// preprocessor. If \arg Namespace is non-null, then it should be the /// namespace that \arg Handler was added to. It is an error to remove /// a handler that has not been registered. void Preprocessor::RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler) { … } bool Preprocessor::LexOnOffSwitch(tok::OnOffSwitch &Result) { … } namespace { /// PragmaOnceHandler - "\#pragma once" marks the file as atomically included. struct PragmaOnceHandler : public PragmaHandler { … }; /// PragmaMarkHandler - "\#pragma mark ..." is ignored by the compiler, and the /// rest of the line is not lexed. struct PragmaMarkHandler : public PragmaHandler { … }; /// PragmaPoisonHandler - "\#pragma poison x" marks x as not usable. struct PragmaPoisonHandler : public PragmaHandler { … }; /// PragmaSystemHeaderHandler - "\#pragma system_header" marks the current file /// as a system header, which silences warnings in it. struct PragmaSystemHeaderHandler : public PragmaHandler { … }; struct PragmaDependencyHandler : public PragmaHandler { … }; struct PragmaDebugHandler : public PragmaHandler { … }; struct PragmaUnsafeBufferUsageHandler : public PragmaHandler { … }; /// PragmaDiagnosticHandler - e.g. '\#pragma GCC diagnostic ignored "-Wformat"' struct PragmaDiagnosticHandler : public PragmaHandler { … }; /// "\#pragma hdrstop [<header-name-string>]" struct PragmaHdrstopHandler : public PragmaHandler { … }; /// "\#pragma warning(...)". MSVC's diagnostics do not map cleanly to clang's /// diagnostics, so we don't really implement this pragma. We parse it and /// ignore it to avoid -Wunknown-pragma warnings. struct PragmaWarningHandler : public PragmaHandler { … }; /// "\#pragma execution_character_set(...)". MSVC supports this pragma only /// for "UTF-8". We parse it and ignore it if UTF-8 is provided and warn /// otherwise to avoid -Wunknown-pragma warnings. struct PragmaExecCharsetHandler : public PragmaHandler { … }; /// PragmaIncludeAliasHandler - "\#pragma include_alias("...")". struct PragmaIncludeAliasHandler : public PragmaHandler { … }; /// PragmaMessageHandler - Handle the microsoft and gcc \#pragma message /// extension. The syntax is: /// \code /// #pragma message(string) /// \endcode /// OR, in GCC mode: /// \code /// #pragma message string /// \endcode /// string is a string, which is fully macro expanded, and permits string /// concatenation, embedded escape characters, etc... See MSDN for more details. /// Also handles \#pragma GCC warning and \#pragma GCC error which take the same /// form as \#pragma message. struct PragmaMessageHandler : public PragmaHandler { … }; /// Handle the clang \#pragma module import extension. The syntax is: /// \code /// #pragma clang module import some.module.name /// \endcode struct PragmaModuleImportHandler : public PragmaHandler { … }; /// Handle the clang \#pragma module begin extension. The syntax is: /// \code /// #pragma clang module begin some.module.name /// ... /// #pragma clang module end /// \endcode struct PragmaModuleBeginHandler : public PragmaHandler { … }; /// Handle the clang \#pragma module end extension. struct PragmaModuleEndHandler : public PragmaHandler { … }; /// Handle the clang \#pragma module build extension. struct PragmaModuleBuildHandler : public PragmaHandler { … }; /// Handle the clang \#pragma module load extension. struct PragmaModuleLoadHandler : public PragmaHandler { … }; /// PragmaPushMacroHandler - "\#pragma push_macro" saves the value of the /// macro on the top of the stack. struct PragmaPushMacroHandler : public PragmaHandler { … }; /// PragmaPopMacroHandler - "\#pragma pop_macro" sets the value of the /// macro to the value on the top of the stack. struct PragmaPopMacroHandler : public PragmaHandler { … }; /// PragmaARCCFCodeAuditedHandler - /// \#pragma clang arc_cf_code_audited begin/end struct PragmaARCCFCodeAuditedHandler : public PragmaHandler { … }; /// PragmaAssumeNonNullHandler - /// \#pragma clang assume_nonnull begin/end struct PragmaAssumeNonNullHandler : public PragmaHandler { … }; /// Handle "\#pragma region [...]" /// /// The syntax is /// \code /// #pragma region [optional name] /// #pragma endregion [optional comment] /// \endcode /// /// \note This is /// <a href="http://msdn.microsoft.com/en-us/library/b6xkz944(v=vs.80).aspx">editor-only</a> /// pragma, just skipped by compiler. struct PragmaRegionHandler : public PragmaHandler { … }; /// "\#pragma managed" /// "\#pragma managed(...)" /// "\#pragma unmanaged" /// MSVC ignores this pragma when not compiling using /clr, which clang doesn't /// support. We parse it and ignore it to avoid -Wunknown-pragma warnings. struct PragmaManagedHandler : public EmptyPragmaHandler { … }; /// This handles parsing pragmas that take a macro name and optional message static IdentifierInfo *HandleMacroAnnotationPragma(Preprocessor &PP, Token &Tok, const char *Pragma, std::string &MessageString) { … } /// "\#pragma clang deprecated(...)" /// /// The syntax is /// \code /// #pragma clang deprecate(MACRO_NAME [, Message]) /// \endcode struct PragmaDeprecatedHandler : public PragmaHandler { … }; /// "\#pragma clang restrict_expansion(...)" /// /// The syntax is /// \code /// #pragma clang restrict_expansion(MACRO_NAME [, Message]) /// \endcode struct PragmaRestrictExpansionHandler : public PragmaHandler { … }; /// "\#pragma clang final(...)" /// /// The syntax is /// \code /// #pragma clang final(MACRO_NAME) /// \endcode struct PragmaFinalHandler : public PragmaHandler { … }; } // namespace /// RegisterBuiltinPragmas - Install the standard preprocessor pragmas: /// \#pragma GCC poison/system_header/dependency and \#pragma once. void Preprocessor::RegisterBuiltinPragmas() { … } /// Ignore all pragmas, useful for modes such as -Eonly which would otherwise /// warn about those pragmas being unknown. void Preprocessor::IgnorePragmas() { … }