Index: clang/include/clang/Lex/Preprocessor.h =================================================================== --- clang/include/clang/Lex/Preprocessor.h +++ clang/include/clang/Lex/Preprocessor.h @@ -193,11 +193,6 @@ LangOptions::FPEvalMethodKind CurrentFPEvalMethod = LangOptions::FPEvalMethodKind::FEM_UnsetOnCommandLine; - // Keeps the value of the last evaluation method before a - // `pragma float_control (precise,off) is applied. - LangOptions::FPEvalMethodKind LastFPEvalMethod = - 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. @@ -2335,14 +2330,6 @@ return LastFPEvalPragmaLocation; } - LangOptions::FPEvalMethodKind getLastFPEvalMethod() const { - return LastFPEvalMethod; - } - - void setLastFPEvalMethod(LangOptions::FPEvalMethodKind Val) { - LastFPEvalMethod = Val; - } - void setCurrentFPEvalMethod(SourceLocation PragmaLoc, LangOptions::FPEvalMethodKind Val) { assert(Val != LangOptions::FEM_UnsetOnCommandLine && Index: clang/lib/Lex/PPMacroExpansion.cpp =================================================================== --- clang/lib/Lex/PPMacroExpansion.cpp +++ clang/lib/Lex/PPMacroExpansion.cpp @@ -1637,35 +1637,14 @@ Tok.setKind(tok::string_literal); } else if (II == Ident__FLT_EVAL_METHOD__) { // __FLT_EVAL_METHOD__ is set to the default value. - if (getTUFPEvalMethod() == - LangOptions::FPEvalMethodKind::FEM_Indeterminable) { - // This is possible if `AllowFPReassoc` or `AllowReciprocal` is enabled. - // These modes can be triggered via the command line option `-ffast-math` - // or via a `pragam float_control`. - // __FLT_EVAL_METHOD__ expands to -1. - // The `minus` operator is the next token we read from the stream. - auto Toks = std::make_unique(1); - OS << "-"; - Tok.setKind(tok::minus); - // Push the token `1` to the stream. - Token NumberToken; - NumberToken.startToken(); - NumberToken.setKind(tok::numeric_constant); - NumberToken.setLiteralData("1"); - NumberToken.setLength(1); - Toks[0] = NumberToken; - EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion*/ false, - /*IsReinject*/ false); - } else { - OS << getTUFPEvalMethod(); - // __FLT_EVAL_METHOD__ expands to a simple numeric value. - Tok.setKind(tok::numeric_constant); - if (getLastFPEvalPragmaLocation().isValid()) { - // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is - // altered by the pragma. - Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); - Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); - } + OS << getTUFPEvalMethod(); + // __FLT_EVAL_METHOD__ expands to a simple numeric value. + Tok.setKind(tok::numeric_constant); + if (getLastFPEvalPragmaLocation().isValid()) { + // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is altered + // by the pragma. + Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); + Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); } } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. Index: clang/lib/Lex/Preprocessor.cpp =================================================================== --- clang/lib/Lex/Preprocessor.cpp +++ clang/lib/Lex/Preprocessor.cpp @@ -207,11 +207,6 @@ else // Set initial value of __FLT_EVAL_METHOD__ from the command line. setCurrentFPEvalMethod(SourceLocation(), getLangOpts().getFPEvalMethod()); - // When `-ffast-math` option is enabled, it triggers several driver math - // options to be enabled. Among those, only one the following two modes - // affect the eval-method: reciprocal or reassociate. - if (getLangOpts().AllowFPReassoc || getLangOpts().AllowRecip) - setCurrentFPEvalMethod(SourceLocation(), LangOptions::FEM_Indeterminable); } void Preprocessor::InitializeForModelFile() { Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -565,13 +565,6 @@ case PFC_Precise: NewFPFeatures.setFPPreciseEnabled(true); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); - if (PP.getCurrentFPEvalMethod() == - LangOptions::FPEvalMethodKind::FEM_Indeterminable && - PP.getLastFPEvalPragmaLocation().isValid()) - // A preceding `pragma float_control(precise,off)` has changed - // the value of the evaluation method. - // Set it back to its old value. - PP.setCurrentFPEvalMethod(SourceLocation(), PP.getLastFPEvalMethod()); break; case PFC_NoPrecise: if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict) @@ -581,10 +574,6 @@ else NewFPFeatures.setFPPreciseEnabled(false); FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); - PP.setLastFPEvalMethod(PP.getCurrentFPEvalMethod()); - // `AllowFPReassoc` or `AllowReciprocal` option is enabled. - PP.setCurrentFPEvalMethod( - Loc, LangOptions::FPEvalMethodKind::FEM_Indeterminable); break; case PFC_Except: if (!isPreciseFPEnabled()) @@ -608,12 +597,6 @@ } FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); NewFPFeatures = FpPragmaStack.CurrentValue; - if (CurFPFeatures.getAllowFPReassociate() || - CurFPFeatures.getAllowReciprocal()) - // Since we are popping the pragma, we don't want to be passing - // a location here. - PP.setCurrentFPEvalMethod(SourceLocation(), - CurFPFeatures.getFPEvalMethod()); break; } CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); Index: clang/test/CodeGen/X86/fexcess-precision.c =================================================================== --- clang/test/CodeGen/X86/fexcess-precision.c +++ clang/test/CodeGen/X86/fexcess-precision.c @@ -380,7 +380,7 @@ // // CHECK-UNSAFE-LABEL: @getFEM( // CHECK-UNSAFE-NEXT: entry: -// CHECK-UNSAFE-NEXT: ret i32 -1 +// CHECK-UNSAFE-NEXT: ret i32 0 // int getFEM() { return __FLT_EVAL_METHOD__; Index: clang/test/CodeGen/eval-method-fast-math.cpp =================================================================== --- clang/test/CodeGen/eval-method-fast-math.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// RUN: %clang_cc1 -fexperimental-strict-floating-point \ -// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK - -// RUN: %clang_cc1 -triple i386--linux -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK-EXT - -// RUN: %clang_cc1 -fexperimental-strict-floating-point \ -// RUN: -mreassociate -freciprocal-math -ffp-contract=fast \ -// RUN: -ffast-math -triple x86_64-linux-gnu \ -// RUN: -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK-FAST - -// RUN: %clang_cc1 -triple i386--linux -mreassociate -freciprocal-math \ -// RUN: -ffp-contract=fast -ffast-math -emit-llvm -o - %s \ -// RUN: | FileCheck %s -check-prefixes=CHECK-FAST - -float a = 1.0f, b = 2.0f, c = 3.0f; -#pragma float_control(precise, off) -float res2 = a + b + c; -int val3 = __FLT_EVAL_METHOD__; -#pragma float_control(precise, on) -float res3 = a + b + c; -int val4 = __FLT_EVAL_METHOD__; - -// CHECK: @val3 = global i32 -1 -// CHECK: @val4 = global i32 0 - -// CHECK-EXT: @val3 = global i32 -1 -// CHECK-EXT: @val4 = global i32 2 - -// CHECK-FAST: @val3 = global i32 -1 -// CHECK-FAST: @val4 = global i32 -1 - -float res; -int add(float a, float b, float c) { - // CHECK: fadd float - // CHECK: load float, ptr - // CHECK: fadd float - // CHECK: store float - // CHECK: ret i32 0 - res = a + b + c; - return __FLT_EVAL_METHOD__; -} - -int add_precise(float a, float b, float c) { -#pragma float_control(precise, on) - // CHECK: fadd float - // CHECK: load float, ptr - // CHECK: fadd float - // CHECK: store float - // CHECK: ret i32 0 - res = a + b + c; - return __FLT_EVAL_METHOD__; -} - -#pragma float_control(push) -#pragma float_control(precise, on) -int add_precise_1(float a, float b, float c) { - // CHECK: fadd float - // CHECK: load float, ptr - // CHECK: fadd float - // CHECK: store float - // CHECK: ret i32 0 - res = a + b + c; - return __FLT_EVAL_METHOD__; -} -#pragma float_control(pop) - -int add_not_precise(float a, float b, float c) { - // Fast-math is enabled with this pragma. -#pragma float_control(precise, off) - // CHECK: fadd fast float - // CHECK: load float, ptr - // CHECK: fadd fast float - // CHECK: float {{.*}}, ptr - // CHECK: ret i32 -1 - res = a + b + c; - return __FLT_EVAL_METHOD__; -} - -#pragma float_control(push) -// Fast-math is enabled with this pragma. -#pragma float_control(precise, off) -int add_not_precise_1(float a, float b, float c) { - // CHECK: fadd fast float - // CHECK: load float, ptr - // CHECK: fadd fast float - // CHECK: float {{.*}}, ptr - // CHECK: ret i32 -1 - res = a + b + c; - return __FLT_EVAL_METHOD__; -} -#pragma float_control(pop) - -int getFPEvalMethod() { - // CHECK: ret i32 0 - return __FLT_EVAL_METHOD__; -} - -float res1; -int whatever(float a, float b, float c) { -#pragma float_control(precise, off) - // CHECK: load float, ptr - // CHECK: fadd fast float - // CHECK: store float {{.*}}, ptr - // CHECK: store i32 -1 - // CHECK: store i32 0 - // CHECK: ret i32 -1 - res1 = a + b + c; - int val1 = __FLT_EVAL_METHOD__; - { -#pragma float_control(precise, on) - int val2 = __FLT_EVAL_METHOD__; - } - return __FLT_EVAL_METHOD__; -} Index: clang/test/Preprocessor/flt_eval_macro.cpp =================================================================== --- clang/test/Preprocessor/flt_eval_macro.cpp +++ clang/test/Preprocessor/flt_eval_macro.cpp @@ -17,7 +17,7 @@ // RUN: %s -o - | FileCheck %s -strict-whitespace // RUN: %clang_cc1 -E -dM -triple=x86_64-apple-macos13.0 -ffast-math \ -// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-MINUS-ONE -strict-whitespace +// RUN: %s -o - | FileCheck %s -check-prefix=CHECK -strict-whitespace // RUN: %clang_cc1 -E -dM -triple i386-pc-windows -target-cpu pentium4 %s -o - \ // RUN: | FileCheck %s -strict-whitespace @@ -64,7 +64,6 @@ int foo() { // CHECK: #define Name "One" - // CHECK-MINUS-ONE: #define Name "MinusOne" // EXT: #define Name "Three" return Name; } Index: revert-03-09.patch =================================================================== --- /dev/null +++ revert-03-09.patch @@ -0,0 +1,8624 @@ +commit 4b7d80b8bca8bd76e2e1ab2dcde1fb6524971e08 +Author: Zahira Ammarguellat +Date: Thu Mar 9 09:24:01 2023 -0500 + + Revert "Currently the control of the eval-method is mixed with fast-math." + + Setting __FLT_EVAL_METHOD__ to -1 with fast-math will set + __GLIBC_FLT_EVAL_METHOD to 2 and long double ends up being used for + float_t and double_t. This creates some ABI breakage with various C libraries. + See details here: https://github.com/llvm/llvm-project/issues/60781 + + This reverts commit bbf0d1932a3c1be970ed8a580e51edf571b80fd5. + +diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h +index d332db496fc7..b3c3a80deb11 100644 +--- a/clang/include/clang/Lex/Preprocessor.h ++++ b/clang/include/clang/Lex/Preprocessor.h +@@ -1,2935 +1,2922 @@ + //===- Preprocessor.h - C Language Family Preprocessor ----------*- C++ -*-===// + // + // 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 + /// Defines the clang::Preprocessor interface. + // + //===----------------------------------------------------------------------===// + + #ifndef LLVM_CLANG_LEX_PREPROCESSOR_H + #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" + #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/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/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/PointerUnion.h" + #include "llvm/ADT/STLExtras.h" + #include "llvm/ADT/SmallPtrSet.h" + #include "llvm/ADT/SmallVector.h" + #include "llvm/ADT/StringRef.h" + #include "llvm/ADT/TinyPtrVector.h" + #include "llvm/ADT/iterator_range.h" + #include "llvm/Support/Allocator.h" + #include "llvm/Support/Casting.h" + #include "llvm/Support/Registry.h" + #include + #include + #include + #include + #include + #include + #include + #include + #include + + namespace llvm { + + template class SmallString; + + } // namespace llvm + + namespace clang { + + class CodeCompletionHandler; + class CommentHandler; + class DirectoryEntry; + class EmptylineHandler; + class ExternalPreprocessorSource; + class FileEntry; + class FileManager; + class HeaderSearch; + class MacroArgs; + class PragmaHandler; + class PragmaNamespace; + class PreprocessingRecord; + class PreprocessorLexer; + class PreprocessorOptions; + class ScratchBuffer; + class TargetInfo; + + namespace Builtin { + class Context; + } + + /// Stores token information for comparing actual tokens with + /// predefined values. Only handles simple tokens and identifiers. + class TokenValue { + tok::TokenKind Kind; + IdentifierInfo *II; + + public: + TokenValue(tok::TokenKind Kind) : Kind(Kind), II(nullptr) { + assert(Kind != tok::raw_identifier && "Raw identifiers are not supported."); + assert(Kind != tok::identifier && + "Identifiers should be created by TokenValue(IdentifierInfo *)"); + assert(!tok::isLiteral(Kind) && "Literals are not supported."); + assert(!tok::isAnnotation(Kind) && "Annotations are not supported."); + } + + TokenValue(IdentifierInfo *II) : Kind(tok::identifier), II(II) {} + + bool operator==(const Token &Tok) const { + return Tok.getKind() == Kind && + (!II || II == Tok.getIdentifierInfo()); + } + }; + + /// Context in which macro name is used. + enum MacroUse { + // other than #define or #undef + MU_Other = 0, + + // macro name specified in #define + MU_Define = 1, + + // macro name specified in #undef + MU_Undef = 2 + }; + + /// Engages in a tight little dance with the lexer to efficiently + /// preprocess tokens. + /// + /// Lexers know only about tokens within a single source file, and don't + /// know anything about preprocessor-level issues like the \#include stack, + /// token expansion, etc. + class Preprocessor { + friend class VAOptDefinitionContext; + friend class VariadicMacroScopeGuard; + + llvm::unique_function OnToken; + std::shared_ptr PPOpts; + DiagnosticsEngine *Diags; + LangOptions &LangOpts; + const TargetInfo *Target = nullptr; + const TargetInfo *AuxTarget = nullptr; + FileManager &FileMgr; + SourceManager &SourceMgr; + std::unique_ptr ScratchBuf; + HeaderSearch &HeaderInfo; + ModuleLoader &TheModuleLoader; + + /// External source of macros. + ExternalPreprocessorSource *ExternalSource; + + /// A BumpPtrAllocator object used to quickly allocate and release + /// objects internal to the Preprocessor. + llvm::BumpPtrAllocator BP; + + /// Identifiers for builtin macros and other builtins. + IdentifierInfo *Ident__LINE__, *Ident__FILE__; // __LINE__, __FILE__ + IdentifierInfo *Ident__DATE__, *Ident__TIME__; // __DATE__, __TIME__ + IdentifierInfo *Ident__INCLUDE_LEVEL__; // __INCLUDE_LEVEL__ + IdentifierInfo *Ident__BASE_FILE__; // __BASE_FILE__ + IdentifierInfo *Ident__FILE_NAME__; // __FILE_NAME__ + IdentifierInfo *Ident__TIMESTAMP__; // __TIMESTAMP__ + IdentifierInfo *Ident__COUNTER__; // __COUNTER__ + IdentifierInfo *Ident_Pragma, *Ident__pragma; // _Pragma, __pragma + IdentifierInfo *Ident__identifier; // __identifier + IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ + IdentifierInfo *Ident__VA_OPT__; // __VA_OPT__ + 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 + IdentifierInfo *Ident__has_warning; // __has_warning + IdentifierInfo *Ident__is_identifier; // __is_identifier + IdentifierInfo *Ident__building_module; // __building_module + IdentifierInfo *Ident__MODULE__; // __MODULE__ + IdentifierInfo *Ident__has_cpp_attribute; // __has_cpp_attribute + IdentifierInfo *Ident__has_c_attribute; // __has_c_attribute + IdentifierInfo *Ident__has_declspec; // __has_declspec_attribute + IdentifierInfo *Ident__is_target_arch; // __is_target_arch + 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; + +- // Keeps the value of the last evaluation method before a +- // `pragma float_control (precise,off) is applied. +- LangOptions::FPEvalMethodKind LastFPEvalMethod = +- 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; + + enum { + /// Maximum depth of \#includes. + MaxAllowedIncludeStackDepth = 200 + }; + + // State that is set before the preprocessor begins. + bool KeepComments : 1; + bool KeepMacroComments : 1; + bool SuppressIncludeNotFoundError : 1; + + // State that changes while the preprocessor runs: + bool InMacroArgs : 1; // True if parsing fn macro invocation args. + + /// Whether the preprocessor owns the header search object. + bool OwnsHeaderSearch : 1; + + /// True if macro expansion is disabled. + bool DisableMacroExpansion : 1; + + /// Temporarily disables DisableMacroExpansion (i.e. enables expansion) + /// when parsing preprocessor directives. + bool MacroExpansionInDirectivesOverride : 1; + + class ResetMacroExpansionHelper; + + /// Whether we have already loaded macros from the external source. + mutable bool ReadMacrosFromExternalSource : 1; + + /// True if pragmas are enabled. + bool PragmasEnabled : 1; + + /// True if the current build action is a preprocessing action. + bool PreprocessedOutput : 1; + + /// True if we are currently preprocessing a #if or #elif directive + bool ParsingIfOrElifDirective; + + /// True if we are pre-expanding macro arguments. + bool InMacroArgPreExpansion; + + /// Mapping/lookup information for all identifiers in + /// the program, including program keywords. + mutable IdentifierTable Identifiers; + + /// This table contains all the selectors in the program. + /// + /// Unlike IdentifierTable above, this table *isn't* populated by the + /// preprocessor. It is declared/expanded here because its role/lifetime is + /// conceptually similar to the IdentifierTable. In addition, the current + /// control flow (in clang::ParseAST()), make it convenient to put here. + /// + /// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to + /// the lifetime of the preprocessor. + SelectorTable Selectors; + + /// Information about builtins. + std::unique_ptr BuiltinInfo; + + /// Tracks all of the pragmas that the client registered + /// with this preprocessor. + std::unique_ptr PragmaHandlers; + + /// Pragma handlers of the original source is stored here during the + /// parsing of a model file. + std::unique_ptr PragmaHandlersBackup; + + /// Tracks all of the comment handlers that the client registered + /// with this preprocessor. + std::vector CommentHandlers; + + /// Empty line handler. + EmptylineHandler *Emptyline = nullptr; + + public: + /// The kind of translation unit we are processing. + const TranslationUnitKind TUKind; + + private: + /// The code-completion handler. + CodeCompletionHandler *CodeComplete = nullptr; + + /// The file that we're performing code-completion for, if any. + const FileEntry *CodeCompletionFile = nullptr; + + /// The offset in file for the code-completion point. + unsigned CodeCompletionOffset = 0; + + /// The location for the code-completion point. This gets instantiated + /// when the CodeCompletionFile gets \#include'ed for preprocessing. + SourceLocation CodeCompletionLoc; + + /// The start location for the file of the code-completion point. + /// + /// This gets instantiated when the CodeCompletionFile gets \#include'ed + /// for preprocessing. + SourceLocation CodeCompletionFileLoc; + + /// The source location of the \c import contextual keyword we just + /// lexed, if any. + SourceLocation ModuleImportLoc; + + /// The import path for named module that we're currently processing. + SmallVector, 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 StdCXXImportSeq { + public: + enum State : int { + // Positive values represent a number of unclosed brackets. + AtTopLevel = 0, + AfterTopLevelTokenSeq = -1, + AfterExport = -2, + AfterImportSeq = -3, + }; + + StdCXXImportSeq(State S) : S(S) {} + + /// Saw any kind of open bracket. + void handleOpenBracket() { + S = static_cast(std::max(S, 0) + 1); + } + /// Saw any kind of close bracket other than '}'. + void handleCloseBracket() { + S = static_cast(std::max(S, 1) - 1); + } + /// Saw a close brace. + void handleCloseBrace() { + handleCloseBracket(); + if (S == AtTopLevel && !AfterHeaderName) + S = AfterTopLevelTokenSeq; + } + /// Saw a semicolon. + void handleSemi() { + if (atTopLevel()) { + S = AfterTopLevelTokenSeq; + AfterHeaderName = false; + } + } + + /// Saw an 'export' identifier. + void handleExport() { + if (S == AfterTopLevelTokenSeq) + S = AfterExport; + else if (S <= 0) + S = AtTopLevel; + } + /// Saw an 'import' identifier. + void handleImport() { + if (S == AfterTopLevelTokenSeq || S == AfterExport) + S = AfterImportSeq; + else if (S <= 0) + S = AtTopLevel; + } + + /// Saw a 'header-name' token; do not recognize any more 'import' tokens + /// until we reach a top-level semicolon. + void handleHeaderName() { + if (S == AfterImportSeq) + AfterHeaderName = true; + handleMisc(); + } + + /// Saw any other token. + void handleMisc() { + if (S <= 0) + S = AtTopLevel; + } + + bool atTopLevel() { return S <= 0; } + bool afterImportSeq() { return S == AfterImportSeq; } + bool afterTopLevelSeq() { return S == AfterTopLevelTokenSeq; } + + private: + State S; + /// Whether we're in the pp-import-suffix following the header-name in a + /// pp-import. If so, a close-brace is not sufficient to end the + /// top-level-token-seq of an import-seq. + bool AfterHeaderName = false; + }; + + /// Our current position within a C++20 import-seq. + 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() : State(NotAModuleDecl) {} + + 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; + std::string Name; + }; + + ModuleDeclSeq ModuleDeclState; + + /// Whether the module import expects an identifier next. Otherwise, + /// it expects a '.' or ';'. + bool ModuleImportExpectsIdentifier = false; + + /// The identifier and source location of the currently-active + /// \#pragma clang arc_cf_code_audited begin. + std::pair PragmaARCCFCodeAuditedInfo; + + /// The source location of the currently-active + /// \#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; + + /// The code completion token containing the information + /// on the stem that is to be code completed. + IdentifierInfo *CodeCompletionII = nullptr; + + /// Range for the code completion token. + SourceRange CodeCompletionTokenRange; + + /// 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; + + /// The number of bytes that we will initially skip when entering the + /// main file, along with a flag that indicates whether skipping this number + /// of bytes will place the lexer at the start of a line. + /// + /// This is used when loading a precompiled preamble. + std::pair SkipMainFilePreamble; + + /// Whether we hit an error due to reaching max allowed include depth. Allows + /// to avoid hitting the same error over and over again. + bool HasReachedMaxIncludeDepth = false; + + /// The number of currently-active calls to Lex. + /// + /// Lex is reentrant, and asking for an (end-of-phase-4) token can often + /// require asking for multiple additional tokens. This counter makes it + /// possible for Lex to detect whether it's producing a token for the end + /// of phase 4 of translation or for some other situation. + unsigned LexLevel = 0; + + /// The number of (LexLevel 0) preprocessor tokens. + unsigned TokenCount = 0; + + /// Preprocess every token regardless of LexLevel. + bool PreprocessToken = false; + + /// The maximum number of (LexLevel 0) tokens before issuing a -Wmax-tokens + /// warning, or zero for unlimited. + unsigned MaxTokens = 0; + SourceLocation MaxTokensOverrideLoc; + + public: + struct PreambleSkipInfo { + SourceLocation HashTokenLoc; + SourceLocation IfTokenLoc; + bool FoundNonSkipPortion; + bool FoundElse; + SourceLocation ElseLoc; + + PreambleSkipInfo(SourceLocation HashTokenLoc, SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc) + : HashTokenLoc(HashTokenLoc), IfTokenLoc(IfTokenLoc), + FoundNonSkipPortion(FoundNonSkipPortion), FoundElse(FoundElse), + ElseLoc(ElseLoc) {} + }; + + using IncludedFilesSet = llvm::DenseSet; + + private: + friend class ASTReader; + friend class MacroArgs; + + class PreambleConditionalStackStore { + enum State { + Off = 0, + Recording = 1, + Replaying = 2, + }; + + public: + PreambleConditionalStackStore() = default; + + void startRecording() { ConditionalStackState = Recording; } + void startReplaying() { ConditionalStackState = Replaying; } + bool isRecording() const { return ConditionalStackState == Recording; } + bool isReplaying() const { return ConditionalStackState == Replaying; } + + ArrayRef getStack() const { + return ConditionalStack; + } + + void doneReplaying() { + ConditionalStack.clear(); + ConditionalStackState = Off; + } + + void setStack(ArrayRef s) { + if (!isRecording() && !isReplaying()) + return; + ConditionalStack.clear(); + ConditionalStack.append(s.begin(), s.end()); + } + + bool hasRecordedPreamble() const { return !ConditionalStack.empty(); } + + bool reachedEOFWhileSkipping() const { return SkipInfo.has_value(); } + + void clearSkipInfo() { SkipInfo.reset(); } + + std::optional SkipInfo; + + private: + SmallVector ConditionalStack; + State ConditionalStackState = Off; + } PreambleConditionalStack; + + /// The current top of the stack that we're lexing from if + /// not expanding a macro and we are lexing directly from source code. + /// + /// Only one of CurLexer, or CurTokenLexer will be non-null. + std::unique_ptr CurLexer; + + /// The current top of the stack what we're lexing from + /// if not expanding a macro. + /// + /// This is an alias for CurLexer. + PreprocessorLexer *CurPPLexer = nullptr; + + /// 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. + ConstSearchDirIterator CurDirLookup = nullptr; + + /// The current macro we are expanding, if we are expanding a macro. + /// + /// One of CurLexer and CurTokenLexer must be null. + std::unique_ptr CurTokenLexer; + + /// The kind of lexer we're currently working with. + enum CurLexerKind { + CLK_Lexer, + CLK_TokenLexer, + CLK_CachingLexer, + CLK_DependencyDirectivesLexer, + CLK_LexAfterModuleImport + } CurLexerKind = CLK_Lexer; + + /// If the current lexer is for a submodule that is being built, this + /// is that submodule. + Module *CurLexerSubmodule = nullptr; + + /// Keeps track of the stack of files currently + /// \#included, and macros currently being expanded from, not counting + /// CurLexer/CurTokenLexer. + struct IncludeStackInfo { + enum CurLexerKind CurLexerKind; + Module *TheSubmodule; + std::unique_ptr TheLexer; + PreprocessorLexer *ThePPLexer; + std::unique_ptr TheTokenLexer; + ConstSearchDirIterator TheDirLookup; + + // The following constructors are completely useless copies of the default + // versions, only needed to pacify MSVC. + IncludeStackInfo(enum CurLexerKind CurLexerKind, Module *TheSubmodule, + std::unique_ptr &&TheLexer, + PreprocessorLexer *ThePPLexer, + std::unique_ptr &&TheTokenLexer, + ConstSearchDirIterator TheDirLookup) + : CurLexerKind(std::move(CurLexerKind)), + TheSubmodule(std::move(TheSubmodule)), TheLexer(std::move(TheLexer)), + ThePPLexer(std::move(ThePPLexer)), + TheTokenLexer(std::move(TheTokenLexer)), + TheDirLookup(std::move(TheDirLookup)) {} + }; + std::vector IncludeMacroStack; + + /// Actions invoked when some preprocessor activity is + /// encountered (e.g. a file is \#included, etc). + std::unique_ptr Callbacks; + + struct MacroExpandsInfo { + Token Tok; + MacroDefinition MD; + SourceRange Range; + + MacroExpandsInfo(Token Tok, MacroDefinition MD, SourceRange Range) + : Tok(Tok), MD(MD), Range(Range) {} + }; + SmallVector DelayedMacroExpandsCallbacks; + + /// Information about a name that has been used to define a module macro. + struct ModuleMacroInfo { + /// The most recent macro directive for this identifier. + MacroDirective *MD; + + /// The active module macros for this identifier. + llvm::TinyPtrVector ActiveModuleMacros; + + /// The generation number at which we last updated ActiveModuleMacros. + /// \see Preprocessor::VisibleModules. + unsigned ActiveModuleMacrosGeneration = 0; + + /// Whether this macro name is ambiguous. + bool IsAmbiguous = false; + + /// The module macros that are overridden by this macro. + llvm::TinyPtrVector OverriddenMacros; + + ModuleMacroInfo(MacroDirective *MD) : MD(MD) {} + }; + + /// The state of a macro for an identifier. + class MacroState { + mutable llvm::PointerUnion State; + + ModuleMacroInfo *getModuleInfo(Preprocessor &PP, + const IdentifierInfo *II) const { + if (II->isOutOfDate()) + PP.updateOutOfDateIdentifier(const_cast(*II)); + // FIXME: Find a spare bit on IdentifierInfo and store a + // HasModuleMacros flag. + if (!II->hasMacroDefinition() || + (!PP.getLangOpts().Modules && + !PP.getLangOpts().ModulesLocalVisibility) || + !PP.CurSubmoduleState->VisibleModules.getGeneration()) + return nullptr; + + auto *Info = State.dyn_cast(); + if (!Info) { + Info = new (PP.getPreprocessorAllocator()) + ModuleMacroInfo(State.get()); + State = Info; + } + + if (PP.CurSubmoduleState->VisibleModules.getGeneration() != + Info->ActiveModuleMacrosGeneration) + PP.updateModuleMacroInfo(II, *Info); + return Info; + } + + public: + MacroState() : MacroState(nullptr) {} + MacroState(MacroDirective *MD) : State(MD) {} + + MacroState(MacroState &&O) noexcept : State(O.State) { + O.State = (MacroDirective *)nullptr; + } + + MacroState &operator=(MacroState &&O) noexcept { + auto S = O.State; + O.State = (MacroDirective *)nullptr; + State = S; + return *this; + } + + ~MacroState() { + if (auto *Info = State.dyn_cast()) + Info->~ModuleMacroInfo(); + } + + MacroDirective *getLatest() const { + if (auto *Info = State.dyn_cast()) + return Info->MD; + return State.get(); + } + + void setLatest(MacroDirective *MD) { + if (auto *Info = State.dyn_cast()) + Info->MD = MD; + else + State = MD; + } + + bool isAmbiguous(Preprocessor &PP, const IdentifierInfo *II) const { + auto *Info = getModuleInfo(PP, II); + return Info ? Info->IsAmbiguous : false; + } + + ArrayRef + getActiveModuleMacros(Preprocessor &PP, const IdentifierInfo *II) const { + if (auto *Info = getModuleInfo(PP, II)) + return Info->ActiveModuleMacros; + return std::nullopt; + } + + MacroDirective::DefInfo findDirectiveAtLoc(SourceLocation Loc, + SourceManager &SourceMgr) const { + // FIXME: Incorporate module macros into the result of this. + if (auto *Latest = getLatest()) + return Latest->findDirectiveAtLoc(Loc, SourceMgr); + return {}; + } + + void overrideActiveModuleMacros(Preprocessor &PP, IdentifierInfo *II) { + if (auto *Info = getModuleInfo(PP, II)) { + Info->OverriddenMacros.insert(Info->OverriddenMacros.end(), + Info->ActiveModuleMacros.begin(), + Info->ActiveModuleMacros.end()); + Info->ActiveModuleMacros.clear(); + Info->IsAmbiguous = false; + } + } + + ArrayRef getOverriddenMacros() const { + if (auto *Info = State.dyn_cast()) + return Info->OverriddenMacros; + return std::nullopt; + } + + void setOverriddenMacros(Preprocessor &PP, + ArrayRef Overrides) { + auto *Info = State.dyn_cast(); + if (!Info) { + if (Overrides.empty()) + return; + Info = new (PP.getPreprocessorAllocator()) + ModuleMacroInfo(State.get()); + State = Info; + } + Info->OverriddenMacros.clear(); + Info->OverriddenMacros.insert(Info->OverriddenMacros.end(), + Overrides.begin(), Overrides.end()); + Info->ActiveModuleMacrosGeneration = 0; + } + }; + + /// For each IdentifierInfo that was associated with a macro, we + /// keep a mapping to the history of all macro definitions and #undefs in + /// the reverse order (the latest one is in the head of the list). + /// + /// This mapping lives within the \p CurSubmoduleState. + using MacroMap = llvm::DenseMap; + + struct SubmoduleState; + + /// Information about a submodule that we're currently building. + struct BuildingSubmoduleInfo { + /// The module that we are building. + Module *M; + + /// The location at which the module was included. + SourceLocation ImportLoc; + + /// Whether we entered this submodule via a pragma. + bool IsPragma; + + /// The previous SubmoduleState. + SubmoduleState *OuterSubmoduleState; + + /// The number of pending module macro names when we started building this. + unsigned OuterPendingModuleMacroNames; + + BuildingSubmoduleInfo(Module *M, SourceLocation ImportLoc, bool IsPragma, + SubmoduleState *OuterSubmoduleState, + unsigned OuterPendingModuleMacroNames) + : M(M), ImportLoc(ImportLoc), IsPragma(IsPragma), + OuterSubmoduleState(OuterSubmoduleState), + OuterPendingModuleMacroNames(OuterPendingModuleMacroNames) {} + }; + SmallVector BuildingSubmoduleStack; + + /// Information about a submodule's preprocessor state. + struct SubmoduleState { + /// The macros for the submodule. + MacroMap Macros; + + /// The set of modules that are visible within the submodule. + VisibleModuleSet VisibleModules; + + // FIXME: CounterValue? + // FIXME: PragmaPushMacroInfo? + }; + std::map Submodules; + + /// The preprocessor state for preprocessing outside of any submodule. + SubmoduleState NullSubmoduleState; + + /// The current submodule state. Will be \p NullSubmoduleState if we're not + /// 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 AffectingClangModules; + + /// The set of known macros exported from modules. + llvm::FoldingSet ModuleMacros; + + /// The names of potential module macros that we've not yet processed. + llvm::SmallVector PendingModuleMacroNames; + + /// The list of module macros, for each identifier, that are not overridden by + /// any other module macro. + llvm::DenseMap> + LeafModuleMacros; + + /// Macros that we want to warn because they are not used at the end + /// of the translation unit. + /// + /// We store just their SourceLocations instead of + /// something like MacroInfo*. The benefit of this is that when we are + /// deserializing from PCH, we don't need to deserialize identifier & macros + /// just so that we can report that they are unused, we just warn using + /// the SourceLocations of this set (that will be filled by the ASTReader). + using WarnUnusedMacroLocsTy = llvm::SmallDenseSet; + 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; + + struct MacroAnnotationInfo { + SourceLocation Location; + std::string Message; + }; + + struct MacroAnnotations { + std::optional DeprecationInfo; + std::optional RestrictExpansionInfo; + std::optional 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 AnnotationInfos; + + /// A "freelist" of MacroArg objects that can be + /// reused for quick allocation. + MacroArgs *MacroArgCache = nullptr; + + /// For each IdentifierInfo used in a \#pragma push_macro directive, + /// we keep a MacroInfo stack used to restore the previous macro value. + llvm::DenseMap> + PragmaPushMacroInfo; + + // Various statistics we track for performance analysis. + unsigned NumDirectives = 0; + unsigned NumDefined = 0; + unsigned NumUndefined = 0; + unsigned NumPragma = 0; + unsigned NumIf = 0; + unsigned NumElse = 0; + unsigned NumEndif = 0; + unsigned NumEnteredSourceFiles = 0; + unsigned MaxIncludeStackDepth = 0; + unsigned NumMacroExpanded = 0; + unsigned NumFnMacroExpanded = 0; + unsigned NumBuiltinMacroExpanded = 0; + unsigned NumFastMacroExpanded = 0; + unsigned NumTokenPaste = 0; + unsigned NumFastTokenPaste = 0; + unsigned NumSkipped = 0; + + /// The predefined macros that preprocessor should use from the + /// command line etc. + std::string Predefines; + + /// The file ID for the preprocessor predefines. + FileID PredefinesFileID; + + /// The file ID for the PCH through header. + FileID PCHThroughHeaderFileID; + + /// Whether tokens are being skipped until a #pragma hdrstop is seen. + bool SkippingUntilPragmaHdrStop = false; + + /// Whether tokens are being skipped until the through header is seen. + bool SkippingUntilPCHThroughHeader = false; + + /// \{ + /// Cache of macro expanders to reduce malloc traffic. + enum { TokenLexerCacheSize = 8 }; + unsigned NumCachedTokenLexers; + std::unique_ptr TokenLexerCache[TokenLexerCacheSize]; + /// \} + + /// Keeps macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + SmallVector MacroExpandedTokens; + std::vector> MacroExpandingLexersStack; + + /// A record of the macro definitions and expansions that + /// occurred during preprocessing. + /// + /// This is an optional side structure that can be enabled with + /// \c createPreprocessingRecord() prior to preprocessing. + PreprocessingRecord *Record = nullptr; + + /// Cached tokens state. + using CachedTokensTy = SmallVector; + + /// Cached tokens are stored here when we do backtracking or + /// lookahead. They are "lexed" by the CachingLex() method. + CachedTokensTy CachedTokens; + + /// The position of the cached token that CachingLex() should + /// "lex" next. + /// + /// If it points beyond the CachedTokens vector, it means that a normal + /// Lex() should be invoked. + CachedTokensTy::size_type CachedLexPos = 0; + + /// Stack of backtrack positions, allowing nested backtracks. + /// + /// The EnableBacktrackAtThisPos() method pushes a position to + /// indicate where CachedLexPos should be set when the BackTrack() method is + /// invoked (at which point the last position is popped). + std::vector BacktrackPositions; + + /// 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; + + /// 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 RecordedSkippedRanges; + + void updateOutOfDateIdentifier(IdentifierInfo &II) const; + + public: + Preprocessor(std::shared_ptr PPOpts, + DiagnosticsEngine &diags, LangOptions &opts, SourceManager &SM, + HeaderSearch &Headers, ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup = nullptr, + bool OwnsHeaderSearch = false, + TranslationUnitKind TUKind = TU_Complete); + + ~Preprocessor(); + + /// Initialize the preprocessor using information about the target. + /// + /// \param Target is owned by the caller and must remain valid for the + /// lifetime of the preprocessor. + /// \param AuxTarget is owned by the caller and must remain valid for + /// the lifetime of the preprocessor. + void Initialize(const TargetInfo &Target, + const TargetInfo *AuxTarget = nullptr); + + /// Initialize the preprocessor to parse a model file + /// + /// To parse model files the preprocessor of the original source is reused to + /// preserver the identifier table. However to avoid some duplicate + /// information in the preprocessor some cleanup is needed before it is used + /// to parse model files. This method does that cleanup. + void InitializeForModelFile(); + + /// Cleanup after model file parsing + void FinalizeForModelFile(); + + /// Retrieve the preprocessor options used to initialize this + /// preprocessor. + PreprocessorOptions &getPreprocessorOpts() const { return *PPOpts; } + + DiagnosticsEngine &getDiagnostics() const { return *Diags; } + void setDiagnostics(DiagnosticsEngine &D) { Diags = &D; } + + const LangOptions &getLangOpts() const { return LangOpts; } + const TargetInfo &getTargetInfo() const { return *Target; } + const TargetInfo *getAuxTargetInfo() const { return AuxTarget; } + FileManager &getFileManager() const { return FileMgr; } + SourceManager &getSourceManager() const { return SourceMgr; } + HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; } + + IdentifierTable &getIdentifierTable() { return Identifiers; } + const IdentifierTable &getIdentifierTable() const { return Identifiers; } + SelectorTable &getSelectorTable() { return Selectors; } + Builtin::Context &getBuiltinInfo() { return *BuiltinInfo; } + llvm::BumpPtrAllocator &getPreprocessorAllocator() { return BP; } + + void setExternalSource(ExternalPreprocessorSource *Source) { + ExternalSource = Source; + } + + ExternalPreprocessorSource *getExternalSource() const { + return ExternalSource; + } + + /// Retrieve the module loader associated with this preprocessor. + ModuleLoader &getModuleLoader() const { return TheModuleLoader; } + + bool hadModuleLoaderFatalFailure() const { + return TheModuleLoader.HadFatalFailure; + } + + /// Retrieve the number of Directives that have been processed by the + /// Preprocessor. + unsigned getNumDirectives() const { + return NumDirectives; + } + + /// True if we are currently preprocessing a #if or #elif directive + bool isParsingIfOrElifDirective() const { + return ParsingIfOrElifDirective; + } + + /// Control whether the preprocessor retains comments in output. + void SetCommentRetentionState(bool KeepComments, bool KeepMacroComments) { + this->KeepComments = KeepComments | KeepMacroComments; + this->KeepMacroComments = KeepMacroComments; + } + + bool getCommentRetentionState() const { return KeepComments; } + + void setPragmasEnabled(bool Enabled) { PragmasEnabled = Enabled; } + bool getPragmasEnabled() const { return PragmasEnabled; } + + void SetSuppressIncludeNotFoundError(bool Suppress) { + SuppressIncludeNotFoundError = Suppress; + } + + bool GetSuppressIncludeNotFoundError() { + return SuppressIncludeNotFoundError; + } + + /// Sets whether the preprocessor is responsible for producing output or if + /// it is producing tokens to be consumed by Parse and Sema. + void setPreprocessedOutput(bool IsPreprocessedOutput) { + PreprocessedOutput = IsPreprocessedOutput; + } + + /// Returns true if the preprocessor is responsible for generating output, + /// false if it is producing tokens to be consumed by Parse and Sema. + bool isPreprocessedOutput() const { return PreprocessedOutput; } + + /// Return true if we are lexing directly from the specified lexer. + bool isCurrentLexer(const PreprocessorLexer *L) const { + return CurPPLexer == L; + } + + /// Return the current lexer being lexed from. + /// + /// Note that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentLexer() const { return CurPPLexer; } + + /// Return the current file lexer being lexed from. + /// + /// Note that this ignores any potentially active macro expansions and _Pragma + /// expansions going on at the time. + PreprocessorLexer *getCurrentFileLexer() const; + + /// Return the submodule owning the file being lexed. This may not be + /// the current module if we have changed modules since entering the file. + Module *getCurrentLexerSubmodule() const { return CurLexerSubmodule; } + + /// Returns the FileID for the preprocessor predefines. + FileID getPredefinesFileID() const { return PredefinesFileID; } + + /// \{ + /// Accessors for preprocessor callbacks. + /// + /// Note that this class takes ownership of any PPCallbacks object given to + /// it. + PPCallbacks *getPPCallbacks() const { return Callbacks.get(); } + void addPPCallbacks(std::unique_ptr C) { + if (Callbacks) + C = std::make_unique(std::move(C), + std::move(Callbacks)); + Callbacks = std::move(C); + } + /// \} + + /// Get the number of tokens processed so far. + unsigned getTokenCount() const { return TokenCount; } + + /// Get the max number of tokens before issuing a -Wmax-tokens warning. + unsigned getMaxTokens() const { return MaxTokens; } + + void overrideMaxTokens(unsigned Value, SourceLocation Loc) { + MaxTokens = Value; + MaxTokensOverrideLoc = Loc; + }; + + SourceLocation getMaxTokensOverrideLoc() const { return MaxTokensOverrideLoc; } + + /// Register a function that would be called on each token in the final + /// expanded token stream. + /// This also reports annotation tokens produced by the parser. + void setTokenWatcher(llvm::unique_function F) { + OnToken = std::move(F); + } + + void setPreprocessToken(bool Preprocess) { PreprocessToken = Preprocess; } + + bool isMacroDefined(StringRef Id) { + return isMacroDefined(&Identifiers.get(Id)); + } + bool isMacroDefined(const IdentifierInfo *II) { + return II->hasMacroDefinition() && + (!getLangOpts().Modules || (bool)getMacroDefinition(II)); + } + + /// Determine whether II is defined as a macro within the module M, + /// if that is a module that we've already preprocessed. Does not check for + /// macros imported into M. + bool isMacroDefinedInLocalModule(const IdentifierInfo *II, Module *M) { + if (!II->hasMacroDefinition()) + return false; + auto I = Submodules.find(M); + if (I == Submodules.end()) + return false; + auto J = I->second.Macros.find(II); + if (J == I->second.Macros.end()) + return false; + auto *MD = J->second.getLatest(); + return MD && MD->isDefined(); + } + + MacroDefinition getMacroDefinition(const IdentifierInfo *II) { + if (!II->hasMacroDefinition()) + return {}; + + MacroState &S = CurSubmoduleState->Macros[II]; + auto *MD = S.getLatest(); + while (MD && isa(MD)) + MD = MD->getPrevious(); + return MacroDefinition(dyn_cast_or_null(MD), + S.getActiveModuleMacros(*this, II), + S.isAmbiguous(*this, II)); + } + + MacroDefinition getMacroDefinitionAtLoc(const IdentifierInfo *II, + SourceLocation Loc) { + if (!II->hadMacroDefinition()) + return {}; + + MacroState &S = CurSubmoduleState->Macros[II]; + MacroDirective::DefInfo DI; + if (auto *MD = S.getLatest()) + DI = MD->findDirectiveAtLoc(Loc, getSourceManager()); + // FIXME: Compute the set of active module macros at the specified location. + return MacroDefinition(DI.getDirective(), + S.getActiveModuleMacros(*this, II), + S.isAmbiguous(*this, II)); + } + + /// Given an identifier, return its latest non-imported MacroDirective + /// if it is \#define'd and not \#undef'd, or null if it isn't \#define'd. + MacroDirective *getLocalMacroDirective(const IdentifierInfo *II) const { + if (!II->hasMacroDefinition()) + return nullptr; + + auto *MD = getLocalMacroDirectiveHistory(II); + if (!MD || MD->getDefinition().isUndefined()) + return nullptr; + + return MD; + } + + const MacroInfo *getMacroInfo(const IdentifierInfo *II) const { + return const_cast(this)->getMacroInfo(II); + } + + MacroInfo *getMacroInfo(const IdentifierInfo *II) { + if (!II->hasMacroDefinition()) + return nullptr; + if (auto MD = getMacroDefinition(II)) + return MD.getMacroInfo(); + return nullptr; + } + + /// Given an identifier, return the latest non-imported macro + /// directive for that identifier. + /// + /// One can iterate over all previous macro directives from the most recent + /// one. + MacroDirective *getLocalMacroDirectiveHistory(const IdentifierInfo *II) const; + + /// Add a directive to the macro directive history for this identifier. + void appendMacroDirective(IdentifierInfo *II, MacroDirective *MD); + DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, MacroInfo *MI, + SourceLocation Loc) { + DefMacroDirective *MD = AllocateDefMacroDirective(MI, Loc); + appendMacroDirective(II, MD); + return MD; + } + DefMacroDirective *appendDefMacroDirective(IdentifierInfo *II, + MacroInfo *MI) { + return appendDefMacroDirective(II, MI, MI->getDefinitionLoc()); + } + + /// Set a MacroDirective that was loaded from a PCH file. + void setLoadedMacroDirective(IdentifierInfo *II, MacroDirective *ED, + MacroDirective *MD); + + /// Register an exported macro for a module and identifier. + ModuleMacro *addModuleMacro(Module *Mod, IdentifierInfo *II, MacroInfo *Macro, + ArrayRef Overrides, bool &IsNew); + ModuleMacro *getModuleMacro(Module *Mod, const IdentifierInfo *II); + + /// Get the list of leaf (non-overridden) module macros for a name. + ArrayRef getLeafModuleMacros(const IdentifierInfo *II) const { + if (II->isOutOfDate()) + updateOutOfDateIdentifier(const_cast(*II)); + auto I = LeafModuleMacros.find(II); + if (I != LeafModuleMacros.end()) + return I->second; + return std::nullopt; + } + + /// Get the list of submodules that we're currently building. + ArrayRef getBuildingSubmodules() const { + return BuildingSubmoduleStack; + } + + /// \{ + /// Iterators for the macro history table. Currently defined macros have + /// IdentifierInfo::hasMacroDefinition() set and an empty + /// MacroInfo::getUndefLoc() at the head of the list. + using macro_iterator = MacroMap::const_iterator; + + macro_iterator macro_begin(bool IncludeExternalMacros = true) const; + macro_iterator macro_end(bool IncludeExternalMacros = true) const; + + llvm::iterator_range + macros(bool IncludeExternalMacros = true) const { + macro_iterator begin = macro_begin(IncludeExternalMacros); + macro_iterator end = macro_end(IncludeExternalMacros); + return llvm::make_range(begin, end); + } + + /// \} + + /// 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 &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) { + HeaderInfo.getFileInfo(File); + return IncludedFiles.insert(File).second; + } + + /// Return true if this header has already been included. + bool alreadyIncluded(const FileEntry *File) const { + 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 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(std::string P) { Predefines = std::move(P); } + + /// Return information about the specified preprocessor + /// identifier token. + IdentifierInfo *getIdentifierInfo(StringRef Name) const { + return &Identifiers.get(Name); + } + + /// Add the specified pragma handler to this preprocessor. + /// + /// If \p 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 AddPragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void AddPragmaHandler(PragmaHandler *Handler) { + AddPragmaHandler(StringRef(), Handler); + } + + /// Remove the specific pragma handler from this preprocessor. + /// + /// If \p Namespace is non-null, then it should be the namespace that + /// \p Handler was added to. It is an error to remove a handler that + /// has not been registered. + void RemovePragmaHandler(StringRef Namespace, PragmaHandler *Handler); + void RemovePragmaHandler(PragmaHandler *Handler) { + RemovePragmaHandler(StringRef(), Handler); + } + + /// Install empty handlers for all pragmas (making them ignored). + void IgnorePragmas(); + + /// Set empty line handler. + void setEmptylineHandler(EmptylineHandler *Handler) { Emptyline = Handler; } + + EmptylineHandler *getEmptylineHandler() const { return Emptyline; } + + /// Add the specified comment handler to the preprocessor. + void addCommentHandler(CommentHandler *Handler); + + /// Remove the specified comment handler. + /// + /// It is an error to remove a handler that has not been registered. + void removeCommentHandler(CommentHandler *Handler); + + /// Set the code completion handler to the given object. + void setCodeCompletionHandler(CodeCompletionHandler &Handler) { + CodeComplete = &Handler; + } + + /// Retrieve the current code-completion handler. + CodeCompletionHandler *getCodeCompletionHandler() const { + return CodeComplete; + } + + /// Clear out the code completion handler. + void clearCodeCompletionHandler() { + CodeComplete = nullptr; + } + + /// Hook used by the lexer to invoke the "included file" code + /// completion point. + void CodeCompleteIncludedFile(llvm::StringRef Dir, bool IsAngled); + + /// Hook used by the lexer to invoke the "natural language" code + /// completion point. + void CodeCompleteNaturalLanguage(); + + /// Set the code completion token for filtering purposes. + void setCodeCompletionIdentifierInfo(IdentifierInfo *Filter) { + CodeCompletionII = Filter; + } + + /// Set the code completion token range for detecting replacement range later + /// on. + void setCodeCompletionTokenRange(const SourceLocation Start, + const SourceLocation End) { + CodeCompletionTokenRange = {Start, End}; + } + SourceRange getCodeCompletionTokenRange() const { + return CodeCompletionTokenRange; + } + + /// Get the code completion token for filtering purposes. + StringRef getCodeCompletionFilter() { + if (CodeCompletionII) + return CodeCompletionII->getName(); + return {}; + } + + /// Retrieve the preprocessing record, or NULL if there is no + /// preprocessing record. + PreprocessingRecord *getPreprocessingRecord() const { return Record; } + + /// Create a new preprocessing record, which will keep track of + /// all macro expansions, macro definitions, etc. + void createPreprocessingRecord(); + + /// Returns true if the FileEntry is the PCH through header. + bool isPCHThroughHeader(const FileEntry *FE); + + /// True if creating a PCH with a through header. + bool creatingPCHWithThroughHeader(); + + /// True if using a PCH with a through header. + bool usingPCHWithThroughHeader(); + + /// True if creating a PCH with a #pragma hdrstop. + bool creatingPCHWithPragmaHdrStop(); + + /// True if using a PCH with a #pragma hdrstop. + bool usingPCHWithPragmaHdrStop(); + + /// Skip tokens until after the #include of the through header or + /// until after a #pragma hdrstop. + void SkipTokensWhileUsingPCH(); + + /// Process directives while skipping until the through header or + /// #pragma hdrstop is found. + void HandleSkippedDirectiveWhileUsingPCH(Token &Result, + SourceLocation HashLoc); + + /// Enter the specified FileID as the main source file, + /// which implicitly adds the builtin defines etc. + void EnterMainSourceFile(); + + /// Inform the preprocessor callbacks that processing is complete. + void EndSourceFile(); + + /// Add a source file to the top of the include stack and + /// 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, 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. + /// + /// \param Args specifies the tokens input to a function-like macro. + /// \param ILEnd specifies the location of the ')' for a function-like macro + /// or the identifier for an object-like macro. + void EnterMacro(Token &Tok, SourceLocation ILEnd, MacroInfo *Macro, + MacroArgs *Args); + + private: + /// Add a "macro" context to the top of the include stack, + /// which will cause the lexer to start returning the specified tokens. + /// + /// If \p DisableMacroExpansion is true, tokens lexed from the token stream + /// will not be subject to further macro expansion. Otherwise, these tokens + /// will be re-macro-expanded when/if expansion is enabled. + /// + /// If \p OwnsTokens is false, this method assumes that the specified stream + /// of tokens has a permanent owner somewhere, so they do not need to be + /// copied. If it is true, it assumes the array of tokens is allocated with + /// \c new[] and the Preprocessor will delete[] it. + /// + /// If \p IsReinject the resulting tokens will have Token::IsReinjected flag + /// set, see the flag documentation for details. + void EnterTokenStream(const Token *Toks, unsigned NumToks, + bool DisableMacroExpansion, bool OwnsTokens, + bool IsReinject); + + public: + void EnterTokenStream(std::unique_ptr Toks, unsigned NumToks, + bool DisableMacroExpansion, bool IsReinject) { + EnterTokenStream(Toks.release(), NumToks, DisableMacroExpansion, true, + IsReinject); + } + + void EnterTokenStream(ArrayRef Toks, bool DisableMacroExpansion, + bool IsReinject) { + EnterTokenStream(Toks.data(), Toks.size(), DisableMacroExpansion, false, + IsReinject); + } + + /// Pop the current lexer/macro exp off the top of the lexer stack. + /// + /// This should only be used in situations where the current state of the + /// top-of-stack lexer is known. + void RemoveTopOfLexerStack(); + + /// From the point that this method is called, and until + /// CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor + /// keeps track of the lexed tokens so that a subsequent Backtrack() call will + /// make the Preprocessor re-lex the same tokens. + /// + /// Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can + /// be called multiple times and CommitBacktrackedTokens/Backtrack calls will + /// be combined with the EnableBacktrackAtThisPos calls in reverse order. + /// + /// NOTE: *DO NOT* forget to call either CommitBacktrackedTokens or Backtrack + /// at some point after EnableBacktrackAtThisPos. If you don't, caching of + /// tokens will continue indefinitely. + /// + void EnableBacktrackAtThisPos(); + + /// Disable the last EnableBacktrackAtThisPos call. + void CommitBacktrackedTokens(); + + /// Make Preprocessor re-lex the tokens that were lexed since + /// EnableBacktrackAtThisPos() was previously called. + void Backtrack(); + + /// True if EnableBacktrackAtThisPos() was called and + /// caching of tokens is on. + bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); } + + /// Lex the next token for this preprocessor. + void Lex(Token &Result); + + /// Lex a token, forming a header-name token if possible. + bool LexHeaderName(Token &Result, bool AllowMacroExpansion = true); + + bool LexAfterModuleImport(Token &Result); + void CollectPpImportSuffix(SmallVectorImpl &Toks); + + void makeModuleVisible(Module *M, SourceLocation Loc); + + SourceLocation getModuleImportLoc(Module *M) const { + return CurSubmoduleState->VisibleModules.getImportLoc(M); + } + + /// Lex a string literal, which may be the concatenation of multiple + /// string literals and may even come from macro expansion. + /// \returns true on success, false if a error diagnostic has been generated. + bool LexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, bool AllowMacroExpansion) { + if (AllowMacroExpansion) + Lex(Result); + else + LexUnexpandedToken(Result); + return FinishLexStringLiteral(Result, String, DiagnosticTag, + AllowMacroExpansion); + } + + /// Complete the lexing of a string literal where the first token has + /// already been lexed (see LexStringLiteral). + bool FinishLexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, + bool AllowMacroExpansion); + + /// Lex a token. If it's a comment, keep lexing until we get + /// something not a comment. + /// + /// This is useful in -E -C mode where comments would foul up preprocessor + /// directive handling. + void LexNonComment(Token &Result) { + do + Lex(Result); + while (Result.getKind() == tok::comment); + } + + /// Just like Lex, but disables macro expansion of identifier tokens. + void LexUnexpandedToken(Token &Result) { + // Disable macro expansion. + bool OldVal = DisableMacroExpansion; + DisableMacroExpansion = true; + // Lex the token. + Lex(Result); + + // Reenable it. + DisableMacroExpansion = OldVal; + } + + /// Like LexNonComment, but this disables macro expansion of + /// identifier tokens. + void LexUnexpandedNonComment(Token &Result) { + do + LexUnexpandedToken(Result); + while (Result.getKind() == tok::comment); + } + + /// Parses a simple integer literal to get its numeric value. Floating + /// point literals and user defined literals are rejected. Used primarily to + /// handle pragmas that accept integer arguments. + bool parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value); + + /// Disables macro expansion everywhere except for preprocessor directives. + void SetMacroExpansionOnlyInDirectives() { + DisableMacroExpansion = true; + MacroExpansionInDirectivesOverride = true; + } + + /// Peeks ahead N tokens and returns that token without consuming any + /// tokens. + /// + /// LookAhead(0) returns the next token that would be returned by Lex(), + /// LookAhead(1) returns the token after it, etc. This returns normal + /// tokens after phase 5. As such, it is equivalent to using + /// 'Lex', not 'LexUnexpandedToken'. + const Token &LookAhead(unsigned N) { + assert(LexLevel == 0 && "cannot use lookahead while lexing"); + if (CachedLexPos + N < CachedTokens.size()) + return CachedTokens[CachedLexPos+N]; + else + return PeekAhead(N+1); + } + + /// When backtracking is enabled and tokens are cached, + /// this allows to revert a specific number of tokens. + /// + /// Note that the number of tokens being reverted should be up to the last + /// backtrack position, not more. + void RevertCachedTokens(unsigned N) { + assert(isBacktrackEnabled() && + "Should only be called when tokens are cached for backtracking"); + assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back()) + && "Should revert tokens up to the last backtrack position, not more"); + assert(signed(CachedLexPos) - signed(N) >= 0 && + "Corrupted backtrack positions ?"); + CachedLexPos -= N; + } + + /// Enters a token in the token stream to be lexed next. + /// + /// If BackTrack() is called afterwards, the token will remain at the + /// insertion point. + /// If \p IsReinject is true, resulting token will have Token::IsReinjected + /// flag set. See the flag documentation for details. + void EnterToken(const Token &Tok, bool IsReinject) { + if (LexLevel) { + // It's not correct in general to enter caching lex mode while in the + // middle of a nested lexing action. + auto TokCopy = std::make_unique(1); + TokCopy[0] = Tok; + EnterTokenStream(std::move(TokCopy), 1, true, IsReinject); + } else { + EnterCachingLexMode(); + assert(IsReinject && "new tokens in the middle of cached stream"); + CachedTokens.insert(CachedTokens.begin()+CachedLexPos, Tok); + } + } + + /// We notify the Preprocessor that if it is caching tokens (because + /// backtrack is enabled) it should replace the most recent cached tokens + /// with the given annotation token. This function has no effect if + /// backtracking is not enabled. + /// + /// Note that the use of this function is just for optimization, so that the + /// cached tokens doesn't get re-parsed and re-resolved after a backtrack is + /// invoked. + void AnnotateCachedTokens(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + AnnotatePreviousCachedTokens(Tok); + } + + /// Get the location of the last cached token, suitable for setting the end + /// location of an annotation token. + SourceLocation getLastCachedTokenLocation() const { + assert(CachedLexPos != 0); + return CachedTokens[CachedLexPos-1].getLastLoc(); + } + + /// Whether \p Tok is the most recent token (`CachedLexPos - 1`) in + /// CachedTokens. + bool IsPreviousCachedToken(const Token &Tok) const; + + /// Replace token in `CachedLexPos - 1` in CachedTokens by the tokens + /// in \p NewToks. + /// + /// Useful when a token needs to be split in smaller ones and CachedTokens + /// most recent token must to be updated to reflect that. + void ReplacePreviousCachedToken(ArrayRef NewToks); + + /// Replace the last token with an annotation token. + /// + /// Like AnnotateCachedTokens(), this routine replaces an + /// already-parsed (and resolved) token with an annotation + /// token. However, this routine only replaces the last token with + /// the annotation token; it does not affect any other cached + /// tokens. This function has no effect if backtracking is not + /// enabled. + void ReplaceLastTokenWithAnnotation(const Token &Tok) { + assert(Tok.isAnnotation() && "Expected annotation token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// Enter an annotation token into the token stream. + void EnterAnnotationToken(SourceRange Range, tok::TokenKind Kind, + void *AnnotationVal); + + /// 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; + } + + /// Update the current token to represent the provided + /// identifier, in order to cache an action performed by typo correction. + void TypoCorrectToken(const Token &Tok) { + assert(Tok.getIdentifierInfo() && "Expected identifier token"); + if (CachedLexPos != 0 && isBacktrackEnabled()) + CachedTokens[CachedLexPos-1] = Tok; + } + + /// Recompute the current lexer kind based on the CurLexer/ + /// CurTokenLexer pointers. + void recomputeCurLexerKind(); + + /// Returns true if incremental processing is enabled + bool isIncrementalProcessingEnabled() const { + return getLangOpts().IncrementalExtensions; + } + + /// Enables the incremental processing + void enableIncrementalProcessing(bool value = true) { + // FIXME: Drop this interface. + const_cast(getLangOpts()).IncrementalExtensions = value; + } + + /// Specify the point at which code-completion will be performed. + /// + /// \param File the file in which code completion should occur. If + /// this file is included multiple times, code-completion will + /// perform completion the first time it is included. If NULL, this + /// function clears out the code-completion point. + /// + /// \param Line the line at which code completion should occur + /// (1-based). + /// + /// \param Column the column at which code completion should occur + /// (1-based). + /// + /// \returns true if an error occurred, false otherwise. + bool SetCodeCompletionPoint(const FileEntry *File, + unsigned Line, unsigned Column); + + /// Determine if we are performing code completion. + bool isCodeCompletionEnabled() const { return CodeCompletionFile != nullptr; } + + /// Returns the location of the code-completion point. + /// + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionLoc() const { return CodeCompletionLoc; } + + /// Returns the start location of the file of code-completion point. + /// + /// Returns an invalid location if code-completion is not enabled or the file + /// containing the code-completion point has not been lexed yet. + SourceLocation getCodeCompletionFileLoc() const { + return CodeCompletionFileLoc; + } + + /// Returns true if code-completion is enabled and we have hit the + /// code-completion point. + bool isCodeCompletionReached() const { return CodeCompletionReached; } + + /// Note that we hit the code-completion point. + void setCodeCompletionReached() { + assert(isCodeCompletionEnabled() && "Code-completion not enabled!"); + CodeCompletionReached = true; + // Silence any diagnostics that occur after we hit the code-completion. + getDiagnostics().setSuppressAllDiagnostics(true); + } + + /// The location of the currently-active \#pragma clang + /// arc_cf_code_audited begin. + /// + /// Returns an invalid location if there is no such pragma active. + std::pair + getPragmaARCCFCodeAuditedInfo() const { + return PragmaARCCFCodeAuditedInfo; + } + + /// Set the location of the currently-active \#pragma clang + /// arc_cf_code_audited begin. An invalid location ends the pragma. + void setPragmaARCCFCodeAuditedInfo(IdentifierInfo *Ident, + SourceLocation Loc) { + PragmaARCCFCodeAuditedInfo = {Ident, Loc}; + } + + /// The location of the currently-active \#pragma clang + /// assume_nonnull begin. + /// + /// Returns an invalid location if there is no such pragma active. + SourceLocation getPragmaAssumeNonNullLoc() const { + return PragmaAssumeNonNullLoc; + } + + /// Set the location of the currently-active \#pragma clang + /// assume_nonnull begin. An invalid location ends the pragma. + void setPragmaAssumeNonNullLoc(SourceLocation Loc) { + 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; + } + + /// Instruct the preprocessor to skip part of the main source file. + /// + /// \param Bytes The number of bytes in the preamble to skip. + /// + /// \param StartOfLine Whether skipping these bytes puts the lexer at the + /// start of a line. + void setSkipMainFilePreamble(unsigned Bytes, bool StartOfLine) { + SkipMainFilePreamble.first = Bytes; + SkipMainFilePreamble.second = StartOfLine; + } + + /// Forwarding function for diagnostics. This emits a diagnostic at + /// the specified Token's location, translating the token's start + /// position in the current buffer into a SourcePosition object for rendering. + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID) const { + return Diags->Report(Loc, DiagID); + } + + DiagnosticBuilder Diag(const Token &Tok, unsigned DiagID) const { + return Diags->Report(Tok.getLocation(), DiagID); + } + + /// Return the 'spelling' of the token at the given + /// location; does not go up to the spelling location or down to the + /// expansion location. + /// + /// \param buffer A buffer which will be used only if the token requires + /// "cleaning", e.g. if it contains trigraphs or escaped newlines + /// \param invalid If non-null, will be set \c true if an error occurs. + StringRef getSpelling(SourceLocation loc, + SmallVectorImpl &buffer, + bool *invalid = nullptr) const { + return Lexer::getSpelling(loc, buffer, SourceMgr, LangOpts, invalid); + } + + /// Return the 'spelling' of the Tok token. + /// + /// The spelling of a token is the characters used to represent the token in + /// the source file after trigraph expansion and escaped-newline folding. In + /// particular, this wants to get the true, uncanonicalized, spelling of + /// things like digraphs, UCNs, etc. + /// + /// \param Invalid If non-null, will be set \c true if an error occurs. + std::string getSpelling(const Token &Tok, bool *Invalid = nullptr) const { + return Lexer::getSpelling(Tok, SourceMgr, LangOpts, Invalid); + } + + /// Get the spelling of a token into a preallocated buffer, instead + /// of as an std::string. + /// + /// The caller is required to allocate enough space for the token, which is + /// guaranteed to be at least Tok.getLength() bytes long. The length of the + /// actual result is returned. + /// + /// Note that this method may do two possible things: it may either fill in + /// the buffer specified with characters, or it may *change the input pointer* + /// to point to a constant buffer with the data already in it (avoiding a + /// copy). The caller is not allowed to modify the returned buffer pointer + /// if an internal buffer is returned. + unsigned getSpelling(const Token &Tok, const char *&Buffer, + bool *Invalid = nullptr) const { + return Lexer::getSpelling(Tok, Buffer, SourceMgr, LangOpts, Invalid); + } + + /// Get the spelling of a token into a SmallVector. + /// + /// Note that the returned StringRef may not point to the + /// supplied buffer if a copy can be avoided. + StringRef getSpelling(const Token &Tok, + SmallVectorImpl &Buffer, + bool *Invalid = nullptr) const; + + /// Relex the token at the specified location. + /// \returns true if there was a failure, false on success. + bool getRawToken(SourceLocation Loc, Token &Result, + bool IgnoreWhiteSpace = false) { + return Lexer::getRawToken(Loc, Result, SourceMgr, LangOpts, IgnoreWhiteSpace); + } + + /// Given a Token \p Tok that is a numeric constant with length 1, + /// return the character. + char + getSpellingOfSingleCharacterNumericConstant(const Token &Tok, + bool *Invalid = nullptr) const { + assert(Tok.is(tok::numeric_constant) && + Tok.getLength() == 1 && "Called on unsupported token"); + assert(!Tok.needsCleaning() && "Token can't need cleaning with length 1"); + + // If the token is carrying a literal data pointer, just use it. + if (const char *D = Tok.getLiteralData()) + return *D; + + // Otherwise, fall back on getCharacterData, which is slower, but always + // works. + return *SourceMgr.getCharacterData(Tok.getLocation(), Invalid); + } + + /// Retrieve the name of the immediate macro expansion. + /// + /// This routine starts from a source location, and finds the name of the + /// macro responsible for its immediate expansion. It looks through any + /// intervening macro argument expansions to compute this. It returns a + /// StringRef that refers to the SourceManager-owned buffer of the source + /// where that macro name is spelled. Thus, the result shouldn't out-live + /// the SourceManager. + StringRef getImmediateMacroName(SourceLocation Loc) { + return Lexer::getImmediateMacroName(Loc, SourceMgr, getLangOpts()); + } + + /// Plop the specified string into a scratch buffer and set the + /// specified token's location and length to it. + /// + /// If specified, the source location provides a location of the expansion + /// point of the token. + void CreateString(StringRef Str, Token &Tok, + SourceLocation ExpansionLocStart = SourceLocation(), + SourceLocation ExpansionLocEnd = SourceLocation()); + + /// Split the first Length characters out of the token starting at TokLoc + /// and return a location pointing to the split token. Re-lexing from the + /// split token will return the split token rather than the original. + SourceLocation SplitToken(SourceLocation TokLoc, unsigned Length); + + /// Computes the source location just past the end of the + /// token at this source location. + /// + /// This routine can be used to produce a source location that + /// points just past the end of the token referenced by \p Loc, and + /// is generally used when a diagnostic needs to point just after a + /// token where it expected something different that it received. If + /// the returned source location would not be meaningful (e.g., if + /// it points into a macro), this routine returns an invalid + /// source location. + /// + /// \param Offset an offset from the end of the token, where the source + /// location should refer to. The default offset (0) produces a source + /// location pointing just past the end of the token; an offset of 1 produces + /// a source location pointing to the last character in the token, etc. + SourceLocation getLocForEndOfToken(SourceLocation Loc, unsigned Offset = 0) { + return Lexer::getLocForEndOfToken(Loc, Offset, SourceMgr, LangOpts); + } + + /// Returns true if the given MacroID location points at the first + /// token of the macro expansion. + /// + /// \param MacroBegin If non-null and function returns true, it is set to + /// begin location of the macro. + bool isAtStartOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroBegin = nullptr) const { + return Lexer::isAtStartOfMacroExpansion(loc, SourceMgr, LangOpts, + MacroBegin); + } + + /// Returns true if the given MacroID location points at the last + /// token of the macro expansion. + /// + /// \param MacroEnd If non-null and function returns true, it is set to + /// end location of the macro. + bool isAtEndOfMacroExpansion(SourceLocation loc, + SourceLocation *MacroEnd = nullptr) const { + return Lexer::isAtEndOfMacroExpansion(loc, SourceMgr, LangOpts, MacroEnd); + } + + /// Print the token to stderr, used for debugging. + void DumpToken(const Token &Tok, bool DumpFlags = false) const; + void DumpLocation(SourceLocation Loc) const; + void DumpMacro(const MacroInfo &MI) const; + void dumpMacroInfo(const IdentifierInfo *II); + + /// Given a location that specifies the start of a + /// token, return a new location that specifies a character within the token. + SourceLocation AdvanceToTokenCharacter(SourceLocation TokStart, + unsigned Char) const { + return Lexer::AdvanceToTokenCharacter(TokStart, Char, SourceMgr, LangOpts); + } + + /// Increment the counters for the number of token paste operations + /// performed. + /// + /// If fast was specified, this is a 'fast paste' case we handled. + void IncrementPasteCounter(bool isFast) { + if (isFast) + ++NumFastTokenPaste; + else + ++NumTokenPaste; + } + + void PrintStats(); + + size_t getTotalMemory() const; + + /// When the macro expander pastes together a comment (/##/) in Microsoft + /// mode, this method handles updating the current state, returning the + /// token on the next source line. + void HandleMicrosoftCommentPaste(Token &Tok); + + //===--------------------------------------------------------------------===// + // Preprocessor callback methods. These are invoked by a lexer as various + // directives and events are found. + + /// Given a tok::raw_identifier token, look up the + /// identifier information for the token and install it into the token, + /// updating the token kind accordingly. + IdentifierInfo *LookUpIdentifierInfo(Token &Identifier) const; + + private: + llvm::DenseMap PoisonReasons; + + public: + /// Specifies the reason for poisoning an identifier. + /// + /// If that identifier is accessed while poisoned, then this reason will be + /// used instead of the default "poisoned" diagnostic. + void SetPoisonReason(IdentifierInfo *II, unsigned DiagID); + + /// Display reason for poisoned identifier. + void HandlePoisonedIdentifier(Token & Identifier); + + void MaybeHandlePoisonedIdentifier(Token & Identifier) { + if(IdentifierInfo * II = Identifier.getIdentifierInfo()) { + if(II->isPoisoned()) { + HandlePoisonedIdentifier(Identifier); + } + } + } + + private: + /// Identifiers used for SEH handling in Borland. These are only + /// allowed in particular circumstances + // __except block + IdentifierInfo *Ident__exception_code, + *Ident___exception_code, + *Ident_GetExceptionCode; + // __except filter expression + IdentifierInfo *Ident__exception_info, + *Ident___exception_info, + *Ident_GetExceptionInfo; + // __finally + IdentifierInfo *Ident__abnormal_termination, + *Ident___abnormal_termination, + *Ident_AbnormalTermination; + + const char *getCurLexerEndPos(); + void diagnoseMissingHeaderInUmbrellaDir(const Module &Mod); + + public: + void PoisonSEHIdentifiers(bool Poison = true); // Borland + + /// Callback invoked when the lexer reads an identifier and has + /// filled in the tokens IdentifierInfo member. + /// + /// This callback potentially macro expands it or turns it into a named + /// token (like 'for'). + /// + /// \returns true if we actually computed a token, false if we need to + /// lex again. + bool HandleIdentifier(Token &Identifier); + + /// Callback invoked when the lexer hits the end of the current file. + /// + /// 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, bool isEndOfMacro = false); + + /// Callback invoked when the current TokenLexer hits the end of its + /// token stream. + bool HandleEndOfTokenLexer(Token &Result); + + /// Callback 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 HandleDirective(Token &Result); + + /// Ensure that the next token is a tok::eod token. + /// + /// If not, emit a diagnostic and consume up until the eod. + /// If \p EnableMacros is true, then we consider macros that expand to zero + /// tokens as being ok. + /// + /// \return The location of the end of the directive (the terminating + /// newline). + SourceLocation CheckEndOfDirective(const char *DirType, + bool EnableMacros = false); + + /// Read and discard all tokens remaining on the current line until + /// the tok::eod token is found. Returns the range of the skipped tokens. + SourceRange DiscardUntilEndOfDirective(); + + /// Returns true if the preprocessor has seen a use of + /// __DATE__ or __TIME__ in the file so far. + bool SawDateOrTime() const { + return DATELoc != SourceLocation() || TIMELoc != SourceLocation(); + } + 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; + } + +- LangOptions::FPEvalMethodKind getLastFPEvalMethod() const { +- return LastFPEvalMethod; +- } +- +- void setLastFPEvalMethod(LangOptions::FPEvalMethodKind Val) { +- LastFPEvalMethod = Val; +- } +- + 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); + + /// Turn the specified lexer token into a fully checked and spelled + /// filename, e.g. as an operand of \#include. + /// + /// 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. + /// + /// \returns true if the input filename was in <>'s or false if it was + /// in ""'s. + bool GetIncludeFilenameSpelling(SourceLocation Loc,StringRef &Buffer); + + /// Given a "foo" or \ reference, look up the indicated 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 ""). + OptionalFileEntryRef + LookupFile(SourceLocation FilenameLoc, StringRef Filename, bool isAngled, + ConstSearchDirIterator FromDir, const FileEntry *FromFile, + ConstSearchDirIterator *CurDir, SmallVectorImpl *SearchPath, + SmallVectorImpl *RelativePath, + ModuleMap::KnownHeader *SuggestedModule, bool *IsMapped, + 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; + + /// Lex an on-off-switch (C99 6.10.6p2) and verify that it is + /// followed by EOD. Return true if the token is not a valid on-off-switch. + bool LexOnOffSwitch(tok::OnOffSwitch &Result); + + bool CheckMacroName(Token &MacroNameTok, MacroUse isDefineUndef, + bool *ShadowFlag = nullptr); + + void EnterSubmodule(Module *M, SourceLocation ImportLoc, bool ForPragma); + Module *LeaveSubmodule(bool ForPragma); + + private: + friend void TokenLexer::ExpandFunctionArguments(); + + void PushIncludeMacroStack() { + assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); + IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, + std::move(CurLexer), CurPPLexer, + std::move(CurTokenLexer), CurDirLookup); + CurPPLexer = nullptr; + } + + void PopIncludeMacroStack() { + CurLexer = std::move(IncludeMacroStack.back().TheLexer); + CurPPLexer = IncludeMacroStack.back().ThePPLexer; + CurTokenLexer = std::move(IncludeMacroStack.back().TheTokenLexer); + CurDirLookup = IncludeMacroStack.back().TheDirLookup; + CurLexerSubmodule = IncludeMacroStack.back().TheSubmodule; + CurLexerKind = IncludeMacroStack.back().CurLexerKind; + IncludeMacroStack.pop_back(); + } + + void PropagateLineStartLeadingSpaceInfo(Token &Result); + + /// Determine whether we need to create module macros for #defines in the + /// current context. + bool needModuleMacros() const; + + /// Update the set of active module macros and ambiguity flag for a module + /// macro name. + void updateModuleMacroInfo(const IdentifierInfo *II, ModuleMacroInfo &Info); + + DefMacroDirective *AllocateDefMacroDirective(MacroInfo *MI, + SourceLocation Loc); + UndefMacroDirective *AllocateUndefMacroDirective(SourceLocation UndefLoc); + VisibilityMacroDirective *AllocateVisibilityMacroDirective(SourceLocation Loc, + bool isPublic); + + /// Lex and validate a macro name, which occurs after a + /// \#define or \#undef. + /// + /// \param MacroNameTok Token that represents the name defined or undefined. + /// \param IsDefineUndef Kind if preprocessor directive. + /// \param ShadowFlag Points to flag that is set if macro name shadows + /// a keyword. + /// + /// This emits a diagnostic, sets the token kind to eod, + /// and discards the rest of the macro line if the macro name is invalid. + void ReadMacroName(Token &MacroNameTok, MacroUse IsDefineUndef = MU_Other, + bool *ShadowFlag = nullptr); + + /// 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 + /// \param MacroNameTok - Token that represents the macro name + /// \param ImmediatelyAfterHeaderGuard - Macro follows an #ifdef header guard + /// + /// Either returns a pointer to a MacroInfo object OR emits a diagnostic and + /// returns a nullptr if an invalid sequence of tokens is encountered. + MacroInfo *ReadOptionalMacroParameterListAndBody( + const Token &MacroNameTok, bool ImmediatelyAfterHeaderGuard); + + /// The ( starting an argument list of a macro definition has just been read. + /// Lex the rest of the parameters and the closing ), updating \p MI with + /// what we learn and saving in \p LastTok the last token read. + /// 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 + /// FoundNonSkipPortion is true, then we have already emitted code for part of + /// this \#if directive, so \#else/\#elif blocks should never be entered. If + /// \p FoundElse is false, 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 SkipExcludedConditionalBlock(SourceLocation HashTokenLoc, + SourceLocation IfTokenLoc, + bool FoundNonSkipPortion, bool FoundElse, + SourceLocation ElseLoc = SourceLocation()); + + /// Information about the result for evaluating an expression for a + /// preprocessor directive. + struct DirectiveEvalResult { + /// Whether the expression was evaluated as true or not. + bool Conditional; + + /// True if the expression contained identifiers that were undefined. + bool IncludedUndefinedIds; + + /// The source range for the expression. + SourceRange ExprRange; + }; + + /// Evaluate an integer constant expression that may occur after a + /// \#if or \#elif directive and return a \p DirectiveEvalResult object. + /// + /// 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 + getIncludeNextStart(const Token &IncludeNextTok) const; + + /// Install the standard preprocessor pragmas: + /// \#pragma GCC poison/system_header/dependency and \#pragma once. + void RegisterBuiltinPragmas(); + + /// Register builtin macros such as __LINE__ with the identifier table. + void RegisterBuiltinMacros(); + + /// If an identifier token is read that is to be expanded as a macro, handle + /// it and return the next token as 'Tok'. If we lexed a token, return true; + /// otherwise the caller should lex again. + bool HandleMacroExpandedIdentifier(Token &Identifier, const MacroDefinition &MD); + + /// Cache macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + Token *cacheMacroExpandedTokens(TokenLexer *tokLexer, + ArrayRef tokens); + + void removeCachedMacroExpandedTokensOfLastLexer(); + + /// Determine whether the next preprocessor token to be + /// lexed is a '('. If so, consume the token and return true, if not, this + /// method should have no observable side-effect on the lexed tokens. + bool isNextPPTokenLParen(); + + /// After reading "MACRO(", this method is invoked to read all of the formal + /// arguments specified for the macro invocation. Returns null on error. + MacroArgs *ReadMacroCallArgumentList(Token &MacroName, MacroInfo *MI, + SourceLocation &MacroEnd); + + /// If an identifier token is read that is to be expanded + /// as a builtin macro, handle it and return the next token as 'Tok'. + void ExpandBuiltinMacro(Token &Tok); + + /// Read a \c _Pragma directive, slice it up, process it, then + /// return the first token after the directive. + /// This assumes that the \c _Pragma token has just been read into \p Tok. + void Handle_Pragma(Token &Tok); + + /// Like Handle_Pragma except the pragma text is not enclosed within + /// a string literal. + void HandleMicrosoft__pragma(Token &Tok); + + /// 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, ConstSearchDirIterator Dir); + + /// Set the FileID for the preprocessor predefines. + void setPredefinesFileID(FileID FID) { + assert(PredefinesFileID.isInvalid() && "PredefinesFileID already set!"); + PredefinesFileID = FID; + } + + /// Set the FileID for the PCH through header. + void setPCHThroughHeaderFileID(FileID FID); + + /// Returns true if we are lexing from a file and not a + /// pragma or a macro. + static bool IsFileLexer(const Lexer* L, const PreprocessorLexer* P) { + return L ? !L->isPragmaLexer() : P != nullptr; + } + + static bool IsFileLexer(const IncludeStackInfo& I) { + return IsFileLexer(I.TheLexer.get(), I.ThePPLexer); + } + + bool IsFileLexer() const { + return IsFileLexer(CurLexer.get(), CurPPLexer); + } + + //===--------------------------------------------------------------------===// + // Caching stuff. + void CachingLex(Token &Result); + + bool InCachingLexMode() const { + // If the Lexer pointers are 0 and IncludeMacroStack is empty, it means + // that we are past EOF, not that we are in CachingLex mode. + return !CurPPLexer && !CurTokenLexer && !IncludeMacroStack.empty(); + } + + void EnterCachingLexMode(); + void EnterCachingLexModeUnchecked(); + + void ExitCachingLexMode() { + if (InCachingLexMode()) + RemoveTopOfLexerStack(); + } + + const Token &PeekAhead(unsigned N); + void AnnotatePreviousCachedTokens(const Token &Tok); + + //===--------------------------------------------------------------------===// + /// Handle*Directive - implement the various preprocessor directives. These + /// should side-effect the current preprocessor object so that the next call + /// to Lex() will return the appropriate token next. + void HandleLineDirective(); + void HandleDigitDirective(Token &Tok); + void HandleUserDiagnosticDirective(Token &Tok, bool isWarning); + void HandleIdentSCCSDirective(Token &Tok); + void HandleMacroPublicDirective(Token &Tok); + void HandleMacroPrivateDirective(); + + /// An additional notification that can be produced by a header inclusion or + /// import to tell the parser what happened. + struct ImportAction { + enum ActionKind { + None, + ModuleBegin, + ModuleImport, + HeaderUnitImport, + SkippedModuleImport, + Failure, + } Kind; + Module *ModuleForHeader = nullptr; + + ImportAction(ActionKind AK, Module *Mod = nullptr) + : Kind(AK), ModuleForHeader(Mod) { + assert((AK == None || Mod || AK == Failure) && + "no module for module action"); + } + }; + + OptionalFileEntryRef 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 &RelativePath, SmallVectorImpl &SearchPath, + ModuleMap::KnownHeader &SuggestedModule, bool isAngled); + + // File inclusion. + void HandleIncludeDirective(SourceLocation HashLoc, Token &Tok, + ConstSearchDirIterator LookupFrom = nullptr, + const FileEntry *LookupFromFile = nullptr); + ImportAction + HandleHeaderIncludeOrImport(SourceLocation HashLoc, Token &IncludeTok, + Token &FilenameTok, SourceLocation EndLoc, + ConstSearchDirIterator LookupFrom = nullptr, + const FileEntry *LookupFromFile = nullptr); + void HandleIncludeNextDirective(SourceLocation HashLoc, Token &Tok); + void HandleIncludeMacrosDirective(SourceLocation HashLoc, Token &Tok); + void HandleImportDirective(SourceLocation HashLoc, Token &Tok); + void HandleMicrosoftImportDirective(Token &Tok); + + public: + /// Check that the given module is available, producing a diagnostic if not. + /// \return \c true if the check failed (because the module is not available). + /// \c false if the module appears to be usable. + static bool checkModuleIsAvailable(const LangOptions &LangOpts, + const TargetInfo &TargetInfo, + DiagnosticsEngine &Diags, Module *M); + + // 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, bool AllowTextual); + + /// We want to produce a diagnostic at location IncLoc concerning an + /// unreachable effect at location MLoc (eg, where a desired entity was + /// declared or defined). Determine whether the right way to make MLoc + /// reachable is by #include, and if so, what header should be included. + /// + /// This is not necessarily fast, and might load unexpected module maps, so + /// should only be called by code that intends to produce an error. + /// + /// \param IncLoc The location at which the missing effect was detected. + /// \param MLoc A location within an unimported module at which the desired + /// effect occurred. + /// \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); + + bool isRecordingPreamble() const { + return PreambleConditionalStack.isRecording(); + } + + bool hasRecordedPreamble() const { + return PreambleConditionalStack.hasRecordedPreamble(); + } + + ArrayRef getPreambleConditionalStack() const { + return PreambleConditionalStack.getStack(); + } + + void setRecordedPreambleConditionalStack(ArrayRef s) { + PreambleConditionalStack.setStack(s); + } + + void setReplayablePreambleConditionalStack( + ArrayRef s, std::optional SkipInfo) { + PreambleConditionalStack.startReplaying(); + PreambleConditionalStack.setStack(s); + PreambleConditionalStack.SkipInfo = SkipInfo; + } + + std::optional getPreambleSkipInfo() const { + return PreambleConditionalStack.SkipInfo; + } + + private: + /// After processing predefined file, initialize the conditional stack from + /// the preamble. + void replayPreambleConditionalStack(); + + // Macro handling. + void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterHeaderGuard); + void HandleUndefDirective(); + + // Conditional Inclusion. + void HandleIfdefDirective(Token &Result, const Token &HashToken, + bool isIfndef, bool ReadAnyTokensBeforeDirective); + void HandleIfDirective(Token &IfToken, const Token &HashToken, + bool ReadAnyTokensBeforeDirective); + void HandleEndifDirective(Token &EndifToken); + void HandleElseDirective(Token &Result, const Token &HashToken); + void HandleElifFamilyDirective(Token &ElifToken, const Token &HashToken, + tok::PPKeywordKind Kind); + + // Pragmas. + void HandlePragmaDirective(PragmaIntroducer Introducer); + + public: + void HandlePragmaOnce(Token &OnceTok); + void HandlePragmaMark(Token &MarkTok); + void HandlePragmaPoison(); + void HandlePragmaSystemHeader(Token &SysHeaderTok); + void HandlePragmaDependency(Token &DependencyTok); + void HandlePragmaPushMacro(Token &Tok); + void HandlePragmaPopMacro(Token &Tok); + void HandlePragmaIncludeAlias(Token &Tok); + void HandlePragmaModuleBuild(Token &Tok); + void HandlePragmaHdrstop(Token &Tok); + IdentifierInfo *ParsePragmaPushOrPopMacro(Token &Tok); + + // Return true and store the first token only if any CommentHandler + // has inserted some tokens and getCommentRetentionState() is false. + bool HandleComment(Token &result, SourceRange Comment); + + /// A macro is used, update information about macros that need unused + /// 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) const { + if (Identifier.getIdentifierInfo()->isDeprecatedMacro()) + emitMacroDeprecationWarning(Identifier); + + if (Identifier.getIdentifierInfo()->isRestrictExpansion() && + !SourceMgr.isInMainFile(Identifier.getLocation())) + emitRestrictExpansionWarning(Identifier); + } + + static void processPathForFileMacro(SmallVectorImpl &Path, + 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; + + /// 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 = 0; + + /// 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, 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 + /// source ranges for each of the comments encountered in the source file. + class CommentHandler { + public: + virtual ~CommentHandler(); + + // The handler shall return true if it has pushed any tokens + // to be read using e.g. EnterToken or EnterTokenStream. + virtual bool HandleComment(Preprocessor &PP, SourceRange Comment) = 0; + }; + + /// Abstract base class that describes a handler that will receive + /// source ranges for empty lines encountered in the source file. + class EmptylineHandler { + public: + virtual ~EmptylineHandler(); + + // The handler handles empty lines. + virtual void HandleEmptyline(SourceRange Range) = 0; + }; + + /// Registry of pragma handlers added by plugins + using PragmaHandlerRegistry = llvm::Registry; + + } // namespace clang + + #endif // LLVM_CLANG_LEX_PREPROCESSOR_H +diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp +index bbc271e5611e..76d0d53ed31d 100644 +--- a/clang/lib/Lex/PPMacroExpansion.cpp ++++ b/clang/lib/Lex/PPMacroExpansion.cpp +@@ -1,1997 +1,1976 @@ + //===--- PPMacroExpansion.cpp - Top level Macro Expansion -----------------===// + // + // 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 top level handling of macro expansion for the + // preprocessor. + // + //===----------------------------------------------------------------------===// + + #include "clang/Basic/AttributeCommonInfo.h" + #include "clang/Basic/Attributes.h" + #include "clang/Basic/Builtins.h" + #include "clang/Basic/FileManager.h" + #include "clang/Basic/IdentifierTable.h" + #include "clang/Basic/LLVM.h" + #include "clang/Basic/LangOptions.h" + #include "clang/Basic/ObjCRuntime.h" + #include "clang/Basic/SourceLocation.h" + #include "clang/Basic/TargetInfo.h" + #include "clang/Lex/CodeCompletionHandler.h" + #include "clang/Lex/DirectoryLookup.h" + #include "clang/Lex/ExternalPreprocessorSource.h" + #include "clang/Lex/HeaderSearch.h" + #include "clang/Lex/LexDiagnostic.h" + #include "clang/Lex/LiteralSupport.h" + #include "clang/Lex/MacroArgs.h" + #include "clang/Lex/MacroInfo.h" + #include "clang/Lex/Preprocessor.h" + #include "clang/Lex/PreprocessorLexer.h" + #include "clang/Lex/PreprocessorOptions.h" + #include "clang/Lex/Token.h" + #include "llvm/ADT/ArrayRef.h" + #include "llvm/ADT/DenseMap.h" + #include "llvm/ADT/DenseSet.h" + #include "llvm/ADT/FoldingSet.h" + #include "llvm/ADT/STLExtras.h" + #include "llvm/ADT/SmallString.h" + #include "llvm/ADT/SmallVector.h" + #include "llvm/ADT/StringRef.h" + #include "llvm/ADT/StringSwitch.h" + #include "llvm/Support/Casting.h" + #include "llvm/Support/ErrorHandling.h" + #include "llvm/Support/Format.h" + #include "llvm/Support/Path.h" + #include "llvm/Support/raw_ostream.h" + #include + #include + #include + #include + #include + #include + #include + #include + #include + + using namespace clang; + + MacroDirective * + Preprocessor::getLocalMacroDirectiveHistory(const IdentifierInfo *II) const { + if (!II->hadMacroDefinition()) + return nullptr; + auto Pos = CurSubmoduleState->Macros.find(II); + return Pos == CurSubmoduleState->Macros.end() ? nullptr + : Pos->second.getLatest(); + } + + void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){ + assert(MD && "MacroDirective should be non-zero!"); + assert(!MD->getPrevious() && "Already attached to a MacroDirective history."); + + MacroState &StoredMD = CurSubmoduleState->Macros[II]; + auto *OldMD = StoredMD.getLatest(); + MD->setPrevious(OldMD); + StoredMD.setLatest(MD); + StoredMD.overrideActiveModuleMacros(*this, II); + + if (needModuleMacros()) { + // Track that we created a new macro directive, so we know we should + // consider building a ModuleMacro for it when we get to the end of + // the module. + PendingModuleMacroNames.push_back(II); + } + + // Set up the identifier as having associated macro history. + II->setHasMacroDefinition(true); + if (!MD->isDefined() && LeafModuleMacros.find(II) == LeafModuleMacros.end()) + II->setHasMacroDefinition(false); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); + } + + void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, + MacroDirective *ED, + MacroDirective *MD) { + // Normally, when a macro is defined, it goes through appendMacroDirective() + // above, which chains a macro to previous defines, undefs, etc. + // However, in a pch, the whole macro history up to the end of the pch is + // stored, so ASTReader goes through this function instead. + // However, built-in macros are already registered in the Preprocessor + // ctor, and ASTWriter stops writing the macro chain at built-in macros, + // so in that case the chain from the pch needs to be spliced to the existing + // built-in. + + assert(II && MD); + MacroState &StoredMD = CurSubmoduleState->Macros[II]; + + if (auto *OldMD = StoredMD.getLatest()) { + // shouldIgnoreMacro() in ASTWriter also stops at macros from the + // predefines buffer in module builds. However, in module builds, modules + // are loaded completely before predefines are processed, so StoredMD + // will be nullptr for them when they're loaded. StoredMD should only be + // non-nullptr for builtins read from a pch file. + assert(OldMD->getMacroInfo()->isBuiltinMacro() && + "only built-ins should have an entry here"); + assert(!OldMD->getPrevious() && "builtin should only have a single entry"); + ED->setPrevious(OldMD); + StoredMD.setLatest(MD); + } else { + StoredMD = MD; + } + + // Setup the identifier as having associated macro history. + II->setHasMacroDefinition(true); + if (!MD->isDefined() && LeafModuleMacros.find(II) == LeafModuleMacros.end()) + II->setHasMacroDefinition(false); + } + + ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II, + MacroInfo *Macro, + ArrayRef Overrides, + bool &New) { + llvm::FoldingSetNodeID ID; + ModuleMacro::Profile(ID, Mod, II); + + void *InsertPos; + if (auto *MM = ModuleMacros.FindNodeOrInsertPos(ID, InsertPos)) { + New = false; + return MM; + } + + auto *MM = ModuleMacro::create(*this, Mod, II, Macro, Overrides); + ModuleMacros.InsertNode(MM, InsertPos); + + // Each overridden macro is now overridden by one more macro. + bool HidAny = false; + for (auto *O : Overrides) { + HidAny |= (O->NumOverriddenBy == 0); + ++O->NumOverriddenBy; + } + + // If we were the first overrider for any macro, it's no longer a leaf. + auto &LeafMacros = LeafModuleMacros[II]; + if (HidAny) { + llvm::erase_if(LeafMacros, + [](ModuleMacro *MM) { return MM->NumOverriddenBy != 0; }); + } + + // The new macro is always a leaf macro. + LeafMacros.push_back(MM); + // The identifier now has defined macros (that may or may not be visible). + II->setHasMacroDefinition(true); + + New = true; + return MM; + } + + ModuleMacro *Preprocessor::getModuleMacro(Module *Mod, + const IdentifierInfo *II) { + llvm::FoldingSetNodeID ID; + ModuleMacro::Profile(ID, Mod, II); + + void *InsertPos; + return ModuleMacros.FindNodeOrInsertPos(ID, InsertPos); + } + + void Preprocessor::updateModuleMacroInfo(const IdentifierInfo *II, + ModuleMacroInfo &Info) { + assert(Info.ActiveModuleMacrosGeneration != + CurSubmoduleState->VisibleModules.getGeneration() && + "don't need to update this macro name info"); + Info.ActiveModuleMacrosGeneration = + CurSubmoduleState->VisibleModules.getGeneration(); + + auto Leaf = LeafModuleMacros.find(II); + if (Leaf == LeafModuleMacros.end()) { + // No imported macros at all: nothing to do. + return; + } + + Info.ActiveModuleMacros.clear(); + + // Every macro that's locally overridden is overridden by a visible macro. + llvm::DenseMap NumHiddenOverrides; + for (auto *O : Info.OverriddenMacros) + NumHiddenOverrides[O] = -1; + + // Collect all macros that are not overridden by a visible macro. + llvm::SmallVector Worklist; + for (auto *LeafMM : Leaf->second) { + assert(LeafMM->getNumOverridingMacros() == 0 && "leaf macro overridden"); + if (NumHiddenOverrides.lookup(LeafMM) == 0) + Worklist.push_back(LeafMM); + } + while (!Worklist.empty()) { + auto *MM = Worklist.pop_back_val(); + if (CurSubmoduleState->VisibleModules.isVisible(MM->getOwningModule())) { + // We only care about collecting definitions; undefinitions only act + // to override other definitions. + if (MM->getMacroInfo()) + Info.ActiveModuleMacros.push_back(MM); + } else { + for (auto *O : MM->overrides()) + if ((unsigned)++NumHiddenOverrides[O] == O->getNumOverridingMacros()) + Worklist.push_back(O); + } + } + // Our reverse postorder walk found the macros in reverse order. + std::reverse(Info.ActiveModuleMacros.begin(), Info.ActiveModuleMacros.end()); + + // Determine whether the macro name is ambiguous. + MacroInfo *MI = nullptr; + bool IsSystemMacro = true; + bool IsAmbiguous = false; + if (auto *MD = Info.MD) { + while (MD && isa(MD)) + MD = MD->getPrevious(); + if (auto *DMD = dyn_cast_or_null(MD)) { + MI = DMD->getInfo(); + IsSystemMacro &= SourceMgr.isInSystemHeader(DMD->getLocation()); + } + } + for (auto *Active : Info.ActiveModuleMacros) { + auto *NewMI = Active->getMacroInfo(); + + // Before marking the macro as ambiguous, check if this is a case where + // both macros are in system headers. If so, we trust that the system + // did not get it wrong. This also handles cases where Clang's own + // headers have a different spelling of certain system macros: + // #define LONG_MAX __LONG_MAX__ (clang's limits.h) + // #define LONG_MAX 0x7fffffffffffffffL (system's limits.h) + // + // FIXME: Remove the defined-in-system-headers check. clang's limits.h + // overrides the system limits.h's macros, so there's no conflict here. + if (MI && NewMI != MI && + !MI->isIdenticalTo(*NewMI, *this, /*Syntactically=*/true)) + IsAmbiguous = true; + IsSystemMacro &= Active->getOwningModule()->IsSystem || + SourceMgr.isInSystemHeader(NewMI->getDefinitionLoc()); + MI = NewMI; + } + Info.IsAmbiguous = IsAmbiguous && !IsSystemMacro; + } + + void Preprocessor::dumpMacroInfo(const IdentifierInfo *II) { + ArrayRef Leaf; + auto LeafIt = LeafModuleMacros.find(II); + if (LeafIt != LeafModuleMacros.end()) + Leaf = LeafIt->second; + const MacroState *State = nullptr; + auto Pos = CurSubmoduleState->Macros.find(II); + if (Pos != CurSubmoduleState->Macros.end()) + State = &Pos->second; + + llvm::errs() << "MacroState " << State << " " << II->getNameStart(); + if (State && State->isAmbiguous(*this, II)) + llvm::errs() << " ambiguous"; + if (State && !State->getOverriddenMacros().empty()) { + llvm::errs() << " overrides"; + for (auto *O : State->getOverriddenMacros()) + llvm::errs() << " " << O->getOwningModule()->getFullModuleName(); + } + llvm::errs() << "\n"; + + // Dump local macro directives. + for (auto *MD = State ? State->getLatest() : nullptr; MD; + MD = MD->getPrevious()) { + llvm::errs() << " "; + MD->dump(); + } + + // Dump module macros. + llvm::DenseSet Active; + for (auto *MM : + State ? State->getActiveModuleMacros(*this, II) : std::nullopt) + Active.insert(MM); + llvm::DenseSet Visited; + llvm::SmallVector Worklist(Leaf.begin(), Leaf.end()); + while (!Worklist.empty()) { + auto *MM = Worklist.pop_back_val(); + llvm::errs() << " ModuleMacro " << MM << " " + << MM->getOwningModule()->getFullModuleName(); + if (!MM->getMacroInfo()) + llvm::errs() << " undef"; + + if (Active.count(MM)) + llvm::errs() << " active"; + else if (!CurSubmoduleState->VisibleModules.isVisible( + MM->getOwningModule())) + llvm::errs() << " hidden"; + else if (MM->getMacroInfo()) + llvm::errs() << " overridden"; + + if (!MM->overrides().empty()) { + llvm::errs() << " overrides"; + for (auto *O : MM->overrides()) { + llvm::errs() << " " << O->getOwningModule()->getFullModuleName(); + if (Visited.insert(O).second) + Worklist.push_back(O); + } + } + llvm::errs() << "\n"; + if (auto *MI = MM->getMacroInfo()) { + llvm::errs() << " "; + MI->dump(); + llvm::errs() << "\n"; + } + } + } + + /// RegisterBuiltinMacro - Register the specified identifier in the identifier + /// table and mark it as a builtin macro to be expanded. + static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){ + // Get the identifier. + IdentifierInfo *Id = PP.getIdentifierInfo(Name); + + // Mark it as being a macro that is builtin. + MacroInfo *MI = PP.AllocateMacroInfo(SourceLocation()); + MI->setIsBuiltinMacro(); + PP.appendDefMacroDirective(Id, MI); + return Id; + } + + /// RegisterBuiltinMacros - Register builtin macros, such as __LINE__ with the + /// identifier table. + void Preprocessor::RegisterBuiltinMacros() { + Ident__LINE__ = RegisterBuiltinMacro(*this, "__LINE__"); + Ident__FILE__ = RegisterBuiltinMacro(*this, "__FILE__"); + Ident__DATE__ = RegisterBuiltinMacro(*this, "__DATE__"); + Ident__TIME__ = RegisterBuiltinMacro(*this, "__TIME__"); + Ident__COUNTER__ = RegisterBuiltinMacro(*this, "__COUNTER__"); + Ident_Pragma = RegisterBuiltinMacro(*this, "_Pragma"); + Ident__FLT_EVAL_METHOD__ = RegisterBuiltinMacro(*this, "__FLT_EVAL_METHOD__"); + + // C++ Standing Document Extensions. + if (getLangOpts().CPlusPlus) + Ident__has_cpp_attribute = + RegisterBuiltinMacro(*this, "__has_cpp_attribute"); + else + Ident__has_cpp_attribute = nullptr; + + // GCC Extensions. + Ident__BASE_FILE__ = RegisterBuiltinMacro(*this, "__BASE_FILE__"); + Ident__INCLUDE_LEVEL__ = RegisterBuiltinMacro(*this, "__INCLUDE_LEVEL__"); + Ident__TIMESTAMP__ = RegisterBuiltinMacro(*this, "__TIMESTAMP__"); + + // Microsoft Extensions. + if (getLangOpts().MicrosoftExt) { + Ident__identifier = RegisterBuiltinMacro(*this, "__identifier"); + Ident__pragma = RegisterBuiltinMacro(*this, "__pragma"); + } else { + Ident__identifier = nullptr; + Ident__pragma = nullptr; + } + + // Clang Extensions. + Ident__FILE_NAME__ = RegisterBuiltinMacro(*this, "__FILE_NAME__"); + Ident__has_feature = RegisterBuiltinMacro(*this, "__has_feature"); + Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); + Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); + Ident__has_constexpr_builtin = + RegisterBuiltinMacro(*this, "__has_constexpr_builtin"); + Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); + if (!getLangOpts().CPlusPlus) + Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute"); + else + Ident__has_c_attribute = nullptr; + + Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute"); + Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); + Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); + Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); + Ident__is_identifier = RegisterBuiltinMacro(*this, "__is_identifier"); + Ident__is_target_arch = RegisterBuiltinMacro(*this, "__is_target_arch"); + Ident__is_target_vendor = RegisterBuiltinMacro(*this, "__is_target_vendor"); + Ident__is_target_os = RegisterBuiltinMacro(*this, "__is_target_os"); + Ident__is_target_environment = + RegisterBuiltinMacro(*this, "__is_target_environment"); + Ident__is_target_variant_os = + RegisterBuiltinMacro(*this, "__is_target_variant_os"); + Ident__is_target_variant_environment = + RegisterBuiltinMacro(*this, "__is_target_variant_environment"); + + // Modules. + Ident__building_module = RegisterBuiltinMacro(*this, "__building_module"); + if (!getLangOpts().CurrentModule.empty()) + Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__"); + else + Ident__MODULE__ = nullptr; + } + + /// isTrivialSingleTokenExpansion - Return true if MI, which has a single token + /// in its expansion, currently expands to that token literally. + static bool isTrivialSingleTokenExpansion(const MacroInfo *MI, + const IdentifierInfo *MacroIdent, + Preprocessor &PP) { + IdentifierInfo *II = MI->getReplacementToken(0).getIdentifierInfo(); + + // If the token isn't an identifier, it's always literally expanded. + if (!II) return true; + + // If the information about this identifier is out of date, update it from + // the external source. + if (II->isOutOfDate()) + PP.getExternalSource()->updateOutOfDateIdentifier(*II); + + // If the identifier is a macro, and if that macro is enabled, it may be + // expanded so it's not a trivial expansion. + if (auto *ExpansionMI = PP.getMacroInfo(II)) + if (ExpansionMI->isEnabled() && + // Fast expanding "#define X X" is ok, because X would be disabled. + II != MacroIdent) + return false; + + // If this is an object-like macro invocation, it is safe to trivially expand + // it. + if (MI->isObjectLike()) return true; + + // If this is a function-like macro invocation, it's safe to trivially expand + // as long as the identifier is not a macro argument. + return !llvm::is_contained(MI->params(), II); + } + + /// isNextPPTokenLParen - Determine whether the next preprocessor token to be + /// lexed is a '('. If so, consume the token and return true, if not, this + /// method should have no observable side-effect on the lexed tokens. + bool Preprocessor::isNextPPTokenLParen() { + // Do some quick tests for rejection cases. + unsigned Val; + if (CurLexer) + Val = CurLexer->isNextPPTokenLParen(); + else + Val = CurTokenLexer->isNextTokenLParen(); + + if (Val == 2) { + // We have run off the end. If it's a source file we don't + // examine enclosing ones (C99 5.1.1.2p4). Otherwise walk up the + // macro stack. + if (CurPPLexer) + return false; + for (const IncludeStackInfo &Entry : llvm::reverse(IncludeMacroStack)) { + if (Entry.TheLexer) + Val = Entry.TheLexer->isNextPPTokenLParen(); + else + Val = Entry.TheTokenLexer->isNextTokenLParen(); + + if (Val != 2) + break; + + // Ran off the end of a source file? + if (Entry.ThePPLexer) + return false; + } + } + + // Okay, if we know that the token is a '(', lex it and return. Otherwise we + // have found something that isn't a '(' or we found the end of the + // translation unit. In either case, return false. + return Val == 1; + } + + /// HandleMacroExpandedIdentifier - If an identifier token is read that is to be + /// expanded as a macro, handle it and return the next token as 'Identifier'. + bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, + const MacroDefinition &M) { + emitMacroExpansionWarnings(Identifier); + + MacroInfo *MI = M.getMacroInfo(); + + // If this is a macro expansion in the "#if !defined(x)" line for the file, + // then the macro could expand to different things in other contexts, we need + // to disable the optimization in this case. + if (CurPPLexer) CurPPLexer->MIOpt.ExpandedMacro(); + + // If this is a builtin macro, like __LINE__ or _Pragma, handle it specially. + if (MI->isBuiltinMacro()) { + if (Callbacks) + Callbacks->MacroExpands(Identifier, M, Identifier.getLocation(), + /*Args=*/nullptr); + ExpandBuiltinMacro(Identifier); + return true; + } + + /// Args - If this is a function-like macro expansion, this contains, + /// for each macro argument, the list of tokens that were provided to the + /// invocation. + MacroArgs *Args = nullptr; + + // Remember where the end of the expansion occurred. For an object-like + // macro, this is the identifier. For a function-like macro, this is the ')'. + SourceLocation ExpansionEnd = Identifier.getLocation(); + + // If this is a function-like macro, read the arguments. + if (MI->isFunctionLike()) { + // Remember that we are now parsing the arguments to a macro invocation. + // Preprocessor directives used inside macro arguments are not portable, and + // this enables the warning. + InMacroArgs = true; + ArgMacro = &Identifier; + + Args = ReadMacroCallArgumentList(Identifier, MI, ExpansionEnd); + + // Finished parsing args. + InMacroArgs = false; + ArgMacro = nullptr; + + // If there was an error parsing the arguments, bail out. + if (!Args) return true; + + ++NumFnMacroExpanded; + } else { + ++NumMacroExpanded; + } + + // Notice that this macro has been used. + markMacroAsUsed(MI); + + // Remember where the token is expanded. + SourceLocation ExpandLoc = Identifier.getLocation(); + SourceRange ExpansionRange(ExpandLoc, ExpansionEnd); + + if (Callbacks) { + if (InMacroArgs) { + // We can have macro expansion inside a conditional directive while + // reading the function macro arguments. To ensure, in that case, that + // MacroExpands callbacks still happen in source order, queue this + // callback to have it happen after the function macro callback. + DelayedMacroExpandsCallbacks.push_back( + MacroExpandsInfo(Identifier, M, ExpansionRange)); + } else { + Callbacks->MacroExpands(Identifier, M, ExpansionRange, Args); + if (!DelayedMacroExpandsCallbacks.empty()) { + for (const MacroExpandsInfo &Info : DelayedMacroExpandsCallbacks) { + // FIXME: We lose macro args info with delayed callback. + Callbacks->MacroExpands(Info.Tok, Info.MD, Info.Range, + /*Args=*/nullptr); + } + DelayedMacroExpandsCallbacks.clear(); + } + } + } + + // If the macro definition is ambiguous, complain. + if (M.isAmbiguous()) { + Diag(Identifier, diag::warn_pp_ambiguous_macro) + << Identifier.getIdentifierInfo(); + Diag(MI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_chosen) + << Identifier.getIdentifierInfo(); + M.forAllDefinitions([&](const MacroInfo *OtherMI) { + if (OtherMI != MI) + Diag(OtherMI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_other) + << Identifier.getIdentifierInfo(); + }); + } + + // If we started lexing a macro, enter the macro expansion body. + + // If this macro expands to no tokens, don't bother to push it onto the + // expansion stack, only to take it right back off. + if (MI->getNumTokens() == 0) { + // No need for arg info. + if (Args) Args->destroy(*this); + + // Propagate whitespace info as if we had pushed, then popped, + // a macro context. + Identifier.setFlag(Token::LeadingEmptyMacro); + PropagateLineStartLeadingSpaceInfo(Identifier); + ++NumFastMacroExpanded; + return false; + } else if (MI->getNumTokens() == 1 && + isTrivialSingleTokenExpansion(MI, Identifier.getIdentifierInfo(), + *this)) { + // Otherwise, if this macro expands into a single trivially-expanded + // token: expand it now. This handles common cases like + // "#define VAL 42". + + // No need for arg info. + if (Args) Args->destroy(*this); + + // Propagate the isAtStartOfLine/hasLeadingSpace markers of the macro + // identifier to the expanded token. + bool isAtStartOfLine = Identifier.isAtStartOfLine(); + bool hasLeadingSpace = Identifier.hasLeadingSpace(); + + // Replace the result token. + Identifier = MI->getReplacementToken(0); + + // Restore the StartOfLine/LeadingSpace markers. + Identifier.setFlagValue(Token::StartOfLine , isAtStartOfLine); + Identifier.setFlagValue(Token::LeadingSpace, hasLeadingSpace); + + // Update the tokens location to include both its expansion and physical + // locations. + SourceLocation Loc = + SourceMgr.createExpansionLoc(Identifier.getLocation(), ExpandLoc, + ExpansionEnd,Identifier.getLength()); + Identifier.setLocation(Loc); + + // If this is a disabled macro or #define X X, we must mark the result as + // unexpandable. + if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) { + if (MacroInfo *NewMI = getMacroInfo(NewII)) + if (!NewMI->isEnabled() || NewMI == MI) { + Identifier.setFlag(Token::DisableExpand); + // Don't warn for "#define X X" like "#define bool bool" from + // stdbool.h. + if (NewMI != MI || MI->isFunctionLike()) + Diag(Identifier, diag::pp_disabled_macro_expansion); + } + } + + // Since this is not an identifier token, it can't be macro expanded, so + // we're done. + ++NumFastMacroExpanded; + return true; + } + + // Start expanding the macro. + EnterMacro(Identifier, ExpansionEnd, MI, Args); + return false; + } + + enum Bracket { + Brace, + Paren + }; + + /// CheckMatchedBrackets - Returns true if the braces and parentheses in the + /// token vector are properly nested. + static bool CheckMatchedBrackets(const SmallVectorImpl &Tokens) { + SmallVector Brackets; + for (SmallVectorImpl::const_iterator I = Tokens.begin(), + E = Tokens.end(); + I != E; ++I) { + if (I->is(tok::l_paren)) { + Brackets.push_back(Paren); + } else if (I->is(tok::r_paren)) { + if (Brackets.empty() || Brackets.back() == Brace) + return false; + Brackets.pop_back(); + } else if (I->is(tok::l_brace)) { + Brackets.push_back(Brace); + } else if (I->is(tok::r_brace)) { + if (Brackets.empty() || Brackets.back() == Paren) + return false; + Brackets.pop_back(); + } + } + return Brackets.empty(); + } + + /// GenerateNewArgTokens - Returns true if OldTokens can be converted to a new + /// vector of tokens in NewTokens. The new number of arguments will be placed + /// in NumArgs and the ranges which need to surrounded in parentheses will be + /// in ParenHints. + /// Returns false if the token stream cannot be changed. If this is because + /// of an initializer list starting a macro argument, the range of those + /// initializer lists will be place in InitLists. + static bool GenerateNewArgTokens(Preprocessor &PP, + SmallVectorImpl &OldTokens, + SmallVectorImpl &NewTokens, + unsigned &NumArgs, + SmallVectorImpl &ParenHints, + SmallVectorImpl &InitLists) { + if (!CheckMatchedBrackets(OldTokens)) + return false; + + // Once it is known that the brackets are matched, only a simple count of the + // braces is needed. + unsigned Braces = 0; + + // First token of a new macro argument. + SmallVectorImpl::iterator ArgStartIterator = OldTokens.begin(); + + // First closing brace in a new macro argument. Used to generate + // SourceRanges for InitLists. + SmallVectorImpl::iterator ClosingBrace = OldTokens.end(); + NumArgs = 0; + Token TempToken; + // Set to true when a macro separator token is found inside a braced list. + // If true, the fixed argument spans multiple old arguments and ParenHints + // will be updated. + bool FoundSeparatorToken = false; + for (SmallVectorImpl::iterator I = OldTokens.begin(), + E = OldTokens.end(); + I != E; ++I) { + if (I->is(tok::l_brace)) { + ++Braces; + } else if (I->is(tok::r_brace)) { + --Braces; + if (Braces == 0 && ClosingBrace == E && FoundSeparatorToken) + ClosingBrace = I; + } else if (I->is(tok::eof)) { + // EOF token is used to separate macro arguments + if (Braces != 0) { + // Assume comma separator is actually braced list separator and change + // it back to a comma. + FoundSeparatorToken = true; + I->setKind(tok::comma); + I->setLength(1); + } else { // Braces == 0 + // Separator token still separates arguments. + ++NumArgs; + + // If the argument starts with a brace, it can't be fixed with + // parentheses. A different diagnostic will be given. + if (FoundSeparatorToken && ArgStartIterator->is(tok::l_brace)) { + InitLists.push_back( + SourceRange(ArgStartIterator->getLocation(), + PP.getLocForEndOfToken(ClosingBrace->getLocation()))); + ClosingBrace = E; + } + + // Add left paren + if (FoundSeparatorToken) { + TempToken.startToken(); + TempToken.setKind(tok::l_paren); + TempToken.setLocation(ArgStartIterator->getLocation()); + TempToken.setLength(0); + NewTokens.push_back(TempToken); + } + + // Copy over argument tokens + NewTokens.insert(NewTokens.end(), ArgStartIterator, I); + + // Add right paren and store the paren locations in ParenHints + if (FoundSeparatorToken) { + SourceLocation Loc = PP.getLocForEndOfToken((I - 1)->getLocation()); + TempToken.startToken(); + TempToken.setKind(tok::r_paren); + TempToken.setLocation(Loc); + TempToken.setLength(0); + NewTokens.push_back(TempToken); + ParenHints.push_back(SourceRange(ArgStartIterator->getLocation(), + Loc)); + } + + // Copy separator token + NewTokens.push_back(*I); + + // Reset values + ArgStartIterator = I + 1; + FoundSeparatorToken = false; + } + } + } + + return !ParenHints.empty() && InitLists.empty(); + } + + /// ReadFunctionLikeMacroArgs - After reading "MACRO" and knowing that the next + /// token is the '(' of the macro, this method is invoked to read all of the + /// actual arguments specified for the macro invocation. This returns null on + /// error. + MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName, + MacroInfo *MI, + SourceLocation &MacroEnd) { + // The number of fixed arguments to parse. + unsigned NumFixedArgsLeft = MI->getNumParams(); + bool isVariadic = MI->isVariadic(); + + // Outer loop, while there are more arguments, keep reading them. + Token Tok; + + // Read arguments as unexpanded tokens. This avoids issues, e.g., where + // an argument value in a macro could expand to ',' or '(' or ')'. + LexUnexpandedToken(Tok); + assert(Tok.is(tok::l_paren) && "Error computing l-paren-ness?"); + + // ArgTokens - Build up a list of tokens that make up each argument. Each + // argument is separated by an EOF token. Use a SmallVector so we can avoid + // heap allocations in the common case. + SmallVector ArgTokens; + bool ContainsCodeCompletionTok = false; + bool FoundElidedComma = false; + + SourceLocation TooManyArgsLoc; + + unsigned NumActuals = 0; + while (Tok.isNot(tok::r_paren)) { + if (ContainsCodeCompletionTok && Tok.isOneOf(tok::eof, tok::eod)) + break; + + assert(Tok.isOneOf(tok::l_paren, tok::comma) && + "only expect argument separators here"); + + size_t ArgTokenStart = ArgTokens.size(); + SourceLocation ArgStartLoc = Tok.getLocation(); + + // C99 6.10.3p11: Keep track of the number of l_parens we have seen. Note + // that we already consumed the first one. + unsigned NumParens = 0; + + while (true) { + // Read arguments as unexpanded tokens. This avoids issues, e.g., where + // an argument value in a macro could expand to ',' or '(' or ')'. + LexUnexpandedToken(Tok); + + if (Tok.isOneOf(tok::eof, tok::eod)) { // "#if f(" & "#if f(\n" + if (!ContainsCodeCompletionTok) { + Diag(MacroName, diag::err_unterm_macro_invoc); + Diag(MI->getDefinitionLoc(), diag::note_macro_here) + << MacroName.getIdentifierInfo(); + // Do not lose the EOF/EOD. Return it to the client. + MacroName = Tok; + return nullptr; + } + // Do not lose the EOF/EOD. + auto Toks = std::make_unique(1); + Toks[0] = Tok; + EnterTokenStream(std::move(Toks), 1, true, /*IsReinject*/ false); + break; + } else if (Tok.is(tok::r_paren)) { + // If we found the ) token, the macro arg list is done. + if (NumParens-- == 0) { + MacroEnd = Tok.getLocation(); + if (!ArgTokens.empty() && + ArgTokens.back().commaAfterElided()) { + FoundElidedComma = true; + } + break; + } + } else if (Tok.is(tok::l_paren)) { + ++NumParens; + } else if (Tok.is(tok::comma)) { + // In Microsoft-compatibility mode, single commas from nested macro + // expansions should not be considered as argument separators. We test + // for this with the IgnoredComma token flag. + if (Tok.getFlags() & Token::IgnoredComma) { + // However, in MSVC's preprocessor, subsequent expansions do treat + // these commas as argument separators. This leads to a common + // workaround used in macros that need to work in both MSVC and + // compliant preprocessors. Therefore, the IgnoredComma flag can only + // apply once to any given token. + Tok.clearFlag(Token::IgnoredComma); + } else if (NumParens == 0) { + // Comma ends this argument if there are more fixed arguments + // expected. However, if this is a variadic macro, and this is part of + // the variadic part, then the comma is just an argument token. + if (!isVariadic) + break; + if (NumFixedArgsLeft > 1) + break; + } + } else if (Tok.is(tok::comment) && !KeepMacroComments) { + // If this is a comment token in the argument list and we're just in + // -C mode (not -CC mode), discard the comment. + continue; + } else if (!Tok.isAnnotation() && Tok.getIdentifierInfo() != nullptr) { + // Reading macro arguments can cause macros that we are currently + // expanding from to be popped off the expansion stack. Doing so causes + // them to be reenabled for expansion. Here we record whether any + // identifiers we lex as macro arguments correspond to disabled macros. + // If so, we mark the token as noexpand. This is a subtle aspect of + // C99 6.10.3.4p2. + if (MacroInfo *MI = getMacroInfo(Tok.getIdentifierInfo())) + if (!MI->isEnabled()) + Tok.setFlag(Token::DisableExpand); + } else if (Tok.is(tok::code_completion)) { + ContainsCodeCompletionTok = true; + if (CodeComplete) + CodeComplete->CodeCompleteMacroArgument(MacroName.getIdentifierInfo(), + MI, NumActuals); + // Don't mark that we reached the code-completion point because the + // parser is going to handle the token and there will be another + // code-completion callback. + } + + ArgTokens.push_back(Tok); + } + + // If this was an empty argument list foo(), don't add this as an empty + // argument. + if (ArgTokens.empty() && Tok.getKind() == tok::r_paren) + break; + + // If this is not a variadic macro, and too many args were specified, emit + // an error. + if (!isVariadic && NumFixedArgsLeft == 0 && TooManyArgsLoc.isInvalid()) { + if (ArgTokens.size() != ArgTokenStart) + TooManyArgsLoc = ArgTokens[ArgTokenStart].getLocation(); + else + TooManyArgsLoc = ArgStartLoc; + } + + // Empty arguments are standard in C99 and C++0x, and are supported as an + // extension in other modes. + if (ArgTokens.size() == ArgTokenStart && !getLangOpts().C99) + Diag(Tok, getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_fnmacro_arg + : diag::ext_empty_fnmacro_arg); + + // Add a marker EOF token to the end of the token list for this argument. + Token EOFTok; + EOFTok.startToken(); + EOFTok.setKind(tok::eof); + EOFTok.setLocation(Tok.getLocation()); + EOFTok.setLength(0); + ArgTokens.push_back(EOFTok); + ++NumActuals; + if (!ContainsCodeCompletionTok && NumFixedArgsLeft != 0) + --NumFixedArgsLeft; + } + + // Okay, we either found the r_paren. Check to see if we parsed too few + // arguments. + unsigned MinArgsExpected = MI->getNumParams(); + + // If this is not a variadic macro, and too many args were specified, emit + // an error. + if (!isVariadic && NumActuals > MinArgsExpected && + !ContainsCodeCompletionTok) { + // Emit the diagnostic at the macro name in case there is a missing ). + // Emitting it at the , could be far away from the macro name. + Diag(TooManyArgsLoc, diag::err_too_many_args_in_macro_invoc); + Diag(MI->getDefinitionLoc(), diag::note_macro_here) + << MacroName.getIdentifierInfo(); + + // Commas from braced initializer lists will be treated as argument + // separators inside macros. Attempt to correct for this with parentheses. + // TODO: See if this can be generalized to angle brackets for templates + // inside macro arguments. + + SmallVector FixedArgTokens; + unsigned FixedNumArgs = 0; + SmallVector ParenHints, InitLists; + if (!GenerateNewArgTokens(*this, ArgTokens, FixedArgTokens, FixedNumArgs, + ParenHints, InitLists)) { + if (!InitLists.empty()) { + DiagnosticBuilder DB = + Diag(MacroName, + diag::note_init_list_at_beginning_of_macro_argument); + for (SourceRange Range : InitLists) + DB << Range; + } + return nullptr; + } + if (FixedNumArgs != MinArgsExpected) + return nullptr; + + DiagnosticBuilder DB = Diag(MacroName, diag::note_suggest_parens_for_macro); + for (SourceRange ParenLocation : ParenHints) { + DB << FixItHint::CreateInsertion(ParenLocation.getBegin(), "("); + DB << FixItHint::CreateInsertion(ParenLocation.getEnd(), ")"); + } + ArgTokens.swap(FixedArgTokens); + NumActuals = FixedNumArgs; + } + + // See MacroArgs instance var for description of this. + bool isVarargsElided = false; + + if (ContainsCodeCompletionTok) { + // Recover from not-fully-formed macro invocation during code-completion. + Token EOFTok; + EOFTok.startToken(); + EOFTok.setKind(tok::eof); + EOFTok.setLocation(Tok.getLocation()); + EOFTok.setLength(0); + for (; NumActuals < MinArgsExpected; ++NumActuals) + ArgTokens.push_back(EOFTok); + } + + if (NumActuals < MinArgsExpected) { + // There are several cases where too few arguments is ok, handle them now. + if (NumActuals == 0 && MinArgsExpected == 1) { + // #define A(X) or #define A(...) ---> A() + + // If there is exactly one argument, and that argument is missing, + // then we have an empty "()" argument empty list. This is fine, even if + // the macro expects one argument (the argument is just empty). + isVarargsElided = MI->isVariadic(); + } else if ((FoundElidedComma || MI->isVariadic()) && + (NumActuals+1 == MinArgsExpected || // A(x, ...) -> A(X) + (NumActuals == 0 && MinArgsExpected == 2))) {// A(x,...) -> A() + // Varargs where the named vararg parameter is missing: OK as extension. + // #define A(x, ...) + // A("blah") + // + // If the macro contains the comma pasting extension, the diagnostic + // is suppressed; we know we'll get another diagnostic later. + if (!MI->hasCommaPasting()) { + // C++20 allows this construct, but standards before C++20 and all C + // standards do not allow the construct (we allow it as an extension). + Diag(Tok, getLangOpts().CPlusPlus20 + ? diag::warn_cxx17_compat_missing_varargs_arg + : diag::ext_missing_varargs_arg); + Diag(MI->getDefinitionLoc(), diag::note_macro_here) + << MacroName.getIdentifierInfo(); + } + + // Remember this occurred, allowing us to elide the comma when used for + // cases like: + // #define A(x, foo...) blah(a, ## foo) + // #define B(x, ...) blah(a, ## __VA_ARGS__) + // #define C(...) blah(a, ## __VA_ARGS__) + // A(x) B(x) C() + isVarargsElided = true; + } else if (!ContainsCodeCompletionTok) { + // Otherwise, emit the error. + Diag(Tok, diag::err_too_few_args_in_macro_invoc); + Diag(MI->getDefinitionLoc(), diag::note_macro_here) + << MacroName.getIdentifierInfo(); + return nullptr; + } + + // Add a marker EOF token to the end of the token list for this argument. + SourceLocation EndLoc = Tok.getLocation(); + Tok.startToken(); + Tok.setKind(tok::eof); + Tok.setLocation(EndLoc); + Tok.setLength(0); + ArgTokens.push_back(Tok); + + // If we expect two arguments, add both as empty. + if (NumActuals == 0 && MinArgsExpected == 2) + ArgTokens.push_back(Tok); + + } else if (NumActuals > MinArgsExpected && !MI->isVariadic() && + !ContainsCodeCompletionTok) { + // Emit the diagnostic at the macro name in case there is a missing ). + // Emitting it at the , could be far away from the macro name. + Diag(MacroName, diag::err_too_many_args_in_macro_invoc); + Diag(MI->getDefinitionLoc(), diag::note_macro_here) + << MacroName.getIdentifierInfo(); + return nullptr; + } + + return MacroArgs::create(MI, ArgTokens, isVarargsElided, *this); + } + + /// Keeps macro expanded tokens for TokenLexers. + // + /// Works like a stack; a TokenLexer adds the macro expanded tokens that is + /// going to lex in the cache and when it finishes the tokens are removed + /// from the end of the cache. + Token *Preprocessor::cacheMacroExpandedTokens(TokenLexer *tokLexer, + ArrayRef tokens) { + assert(tokLexer); + if (tokens.empty()) + return nullptr; + + size_t newIndex = MacroExpandedTokens.size(); + bool cacheNeedsToGrow = tokens.size() > + MacroExpandedTokens.capacity()-MacroExpandedTokens.size(); + MacroExpandedTokens.append(tokens.begin(), tokens.end()); + + if (cacheNeedsToGrow) { + // Go through all the TokenLexers whose 'Tokens' pointer points in the + // buffer and update the pointers to the (potential) new buffer array. + for (const auto &Lexer : MacroExpandingLexersStack) { + TokenLexer *prevLexer; + size_t tokIndex; + std::tie(prevLexer, tokIndex) = Lexer; + prevLexer->Tokens = MacroExpandedTokens.data() + tokIndex; + } + } + + MacroExpandingLexersStack.push_back(std::make_pair(tokLexer, newIndex)); + return MacroExpandedTokens.data() + newIndex; + } + + void Preprocessor::removeCachedMacroExpandedTokensOfLastLexer() { + assert(!MacroExpandingLexersStack.empty()); + size_t tokIndex = MacroExpandingLexersStack.back().second; + assert(tokIndex < MacroExpandedTokens.size()); + // Pop the cached macro expanded tokens from the end. + MacroExpandedTokens.resize(tokIndex); + MacroExpandingLexersStack.pop_back(); + } + + /// ComputeDATE_TIME - Compute the current time, enter it into the specified + /// scratch buffer, then return DATELoc/TIMELoc locations with the position of + /// the identifier tokens inserted. + static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, + Preprocessor &PP) { + time_t TT; + std::tm *TM; + if (PP.getPreprocessorOpts().SourceDateEpoch) { + TT = *PP.getPreprocessorOpts().SourceDateEpoch; + TM = std::gmtime(&TT); + } else { + TT = std::time(nullptr); + TM = std::localtime(&TT); + } + + static const char * const Months[] = { + "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" + }; + + { + SmallString<32> TmpBuffer; + llvm::raw_svector_ostream TmpStream(TmpBuffer); + if (TM) + TmpStream << llvm::format("\"%s %2d %4d\"", Months[TM->tm_mon], + TM->tm_mday, TM->tm_year + 1900); + else + TmpStream << "??? ?? ????"; + Token TmpTok; + TmpTok.startToken(); + PP.CreateString(TmpStream.str(), TmpTok); + DATELoc = TmpTok.getLocation(); + } + + { + SmallString<32> TmpBuffer; + llvm::raw_svector_ostream TmpStream(TmpBuffer); + if (TM) + TmpStream << llvm::format("\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, + TM->tm_sec); + else + TmpStream << "??:??:??"; + Token TmpTok; + TmpTok.startToken(); + PP.CreateString(TmpStream.str(), TmpTok); + TIMELoc = TmpTok.getLocation(); + } + } + + /// HasFeature - Return true if we recognize and implement the feature + /// specified by the identifier as a standard language feature. + static bool HasFeature(const Preprocessor &PP, StringRef Feature) { + const LangOptions &LangOpts = PP.getLangOpts(); + + // Normalize the feature name, __foo__ becomes foo. + if (Feature.startswith("__") && Feature.endswith("__") && Feature.size() >= 4) + Feature = Feature.substr(2, Feature.size() - 4); + + #define FEATURE(Name, Predicate) .Case(#Name, Predicate) + return llvm::StringSwitch(Feature) + #include "clang/Basic/Features.def" + .Default(false); + #undef FEATURE + } + + /// HasExtension - Return true if we recognize and implement the feature + /// specified by the identifier, either as an extension or a standard language + /// feature. + static bool HasExtension(const Preprocessor &PP, StringRef Extension) { + if (HasFeature(PP, Extension)) + return true; + + // If the use of an extension results in an error diagnostic, extensions are + // effectively unavailable, so just return false here. + if (PP.getDiagnostics().getExtensionHandlingBehavior() >= + diag::Severity::Error) + return false; + + const LangOptions &LangOpts = PP.getLangOpts(); + + // Normalize the extension name, __foo__ becomes foo. + if (Extension.startswith("__") && Extension.endswith("__") && + Extension.size() >= 4) + Extension = Extension.substr(2, Extension.size() - 4); + + // Because we inherit the feature list from HasFeature, this string switch + // must be less restrictive than HasFeature's. + #define EXTENSION(Name, Predicate) .Case(#Name, Predicate) + return llvm::StringSwitch(Extension) + #include "clang/Basic/Features.def" + .Default(false); + #undef EXTENSION + } + + /// EvaluateHasIncludeCommon - Process a '__has_include("path")' + /// or '__has_include_next("path")' expression. + /// Returns true if successful. + static bool EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II, + Preprocessor &PP, + ConstSearchDirIterator LookupFrom, + const FileEntry *LookupFromFile) { + // Save the location of the current token. If a '(' is later found, use + // that location. If not, use the end of this location instead. + SourceLocation LParenLoc = Tok.getLocation(); + + // These expressions are only allowed within a preprocessor directive. + if (!PP.isParsingIfOrElifDirective()) { + PP.Diag(LParenLoc, diag::err_pp_directive_required) << II; + // Return a valid identifier token. + assert(Tok.is(tok::identifier)); + Tok.setIdentifierInfo(II); + return false; + } + + // Get '('. If we don't have a '(', try to form a header-name token. + do { + if (PP.LexHeaderName(Tok)) + return false; + } while (Tok.getKind() == tok::comment); + + // Ensure we have a '('. + if (Tok.isNot(tok::l_paren)) { + // No '(', use end of last token. + LParenLoc = PP.getLocForEndOfToken(LParenLoc); + PP.Diag(LParenLoc, diag::err_pp_expected_after) << II << tok::l_paren; + // If the next token looks like a filename or the start of one, + // assume it is and process it as such. + if (Tok.isNot(tok::header_name)) + return false; + } else { + // Save '(' location for possible missing ')' message. + LParenLoc = Tok.getLocation(); + if (PP.LexHeaderName(Tok)) + return false; + } + + if (Tok.isNot(tok::header_name)) { + PP.Diag(Tok.getLocation(), diag::err_pp_expects_filename); + return false; + } + + // Reserve a buffer to get the spelling. + SmallString<128> FilenameBuffer; + bool Invalid = false; + StringRef Filename = PP.getSpelling(Tok, FilenameBuffer, &Invalid); + if (Invalid) + return false; + + SourceLocation FilenameLoc = Tok.getLocation(); + + // Get ')'. + PP.LexNonComment(Tok); + + // Ensure we have a trailing ). + if (Tok.isNot(tok::r_paren)) { + PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_expected_after) + << II << tok::r_paren; + PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren; + return false; + } + + bool isAngled = PP.GetIncludeFilenameSpelling(Tok.getLocation(), Filename); + // If GetIncludeFilenameSpelling set the start ptr to null, there was an + // error. + if (Filename.empty()) + return false; + + // Search include directories. + OptionalFileEntryRef File = + PP.LookupFile(FilenameLoc, Filename, isAngled, LookupFrom, LookupFromFile, + nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); + + if (PPCallbacks *Callbacks = PP.getPPCallbacks()) { + SrcMgr::CharacteristicKind FileType = SrcMgr::C_User; + if (File) + FileType = + PP.getHeaderSearchInfo().getFileDirFlavor(&File->getFileEntry()); + Callbacks->HasInclude(FilenameLoc, Filename, isAngled, File, FileType); + } + + // Get the result value. A result of true means the file exists. + return File.has_value(); + } + + bool Preprocessor::EvaluateHasInclude(Token &Tok, IdentifierInfo *II) { + return EvaluateHasIncludeCommon(Tok, II, *this, nullptr, nullptr); + } + + bool Preprocessor::EvaluateHasIncludeNext(Token &Tok, IdentifierInfo *II) { + ConstSearchDirIterator Lookup = nullptr; + const FileEntry *LookupFromFile; + std::tie(Lookup, LookupFromFile) = getIncludeNextStart(Tok); + + return EvaluateHasIncludeCommon(Tok, II, *this, Lookup, LookupFromFile); + } + + /// Process single-argument builtin feature-like macros that return + /// integer values. + static void EvaluateFeatureLikeBuiltinMacro(llvm::raw_svector_ostream& OS, + Token &Tok, IdentifierInfo *II, + Preprocessor &PP, bool ExpandArgs, + llvm::function_ref< + int(Token &Tok, + bool &HasLexedNextTok)> Op) { + // Parse the initial '('. + PP.LexUnexpandedToken(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_expected_after) << II + << tok::l_paren; + + // Provide a dummy '0' value on output stream to elide further errors. + if (!Tok.isOneOf(tok::eof, tok::eod)) { + OS << 0; + Tok.setKind(tok::numeric_constant); + } + return; + } + + unsigned ParenDepth = 1; + SourceLocation LParenLoc = Tok.getLocation(); + std::optional Result; + + Token ResultTok; + bool SuppressDiagnostic = false; + while (true) { + // Parse next token. + if (ExpandArgs) + PP.Lex(Tok); + else + PP.LexUnexpandedToken(Tok); + + already_lexed: + switch (Tok.getKind()) { + case tok::eof: + case tok::eod: + // Don't provide even a dummy value if the eod or eof marker is + // reached. Simply provide a diagnostic. + PP.Diag(Tok.getLocation(), diag::err_unterm_macro_invoc); + return; + + case tok::comma: + if (!SuppressDiagnostic) { + PP.Diag(Tok.getLocation(), diag::err_too_many_args_in_macro_invoc); + SuppressDiagnostic = true; + } + continue; + + case tok::l_paren: + ++ParenDepth; + if (Result) + break; + if (!SuppressDiagnostic) { + PP.Diag(Tok.getLocation(), diag::err_pp_nested_paren) << II; + SuppressDiagnostic = true; + } + continue; + + case tok::r_paren: + if (--ParenDepth > 0) + continue; + + // The last ')' has been reached; return the value if one found or + // a diagnostic and a dummy value. + if (Result) { + OS << *Result; + // For strict conformance to __has_cpp_attribute rules, use 'L' + // suffix for dated literals. + if (*Result > 1) + OS << 'L'; + } else { + OS << 0; + if (!SuppressDiagnostic) + PP.Diag(Tok.getLocation(), diag::err_too_few_args_in_macro_invoc); + } + Tok.setKind(tok::numeric_constant); + return; + + default: { + // Parse the macro argument, if one not found so far. + if (Result) + break; + + bool HasLexedNextToken = false; + Result = Op(Tok, HasLexedNextToken); + ResultTok = Tok; + if (HasLexedNextToken) + goto already_lexed; + continue; + } + } + + // Diagnose missing ')'. + if (!SuppressDiagnostic) { + if (auto Diag = PP.Diag(Tok.getLocation(), diag::err_pp_expected_after)) { + if (IdentifierInfo *LastII = ResultTok.getIdentifierInfo()) + Diag << LastII; + else + Diag << ResultTok.getKind(); + Diag << tok::r_paren << ResultTok.getLocation(); + } + PP.Diag(LParenLoc, diag::note_matching) << tok::l_paren; + SuppressDiagnostic = true; + } + } + } + + /// Helper function to return the IdentifierInfo structure of a Token + /// or generate a diagnostic if none available. + static IdentifierInfo *ExpectFeatureIdentifierInfo(Token &Tok, + Preprocessor &PP, + signed DiagID) { + IdentifierInfo *II; + if (!Tok.isAnnotation() && (II = Tok.getIdentifierInfo())) + return II; + + PP.Diag(Tok.getLocation(), DiagID); + return nullptr; + } + + /// Implements the __is_target_arch builtin macro. + static bool isTargetArch(const TargetInfo &TI, const IdentifierInfo *II) { + std::string ArchName = II->getName().lower() + "--"; + llvm::Triple Arch(ArchName); + const llvm::Triple &TT = TI.getTriple(); + if (TT.isThumb()) { + // arm matches thumb or thumbv7. armv7 matches thumbv7. + if ((Arch.getSubArch() == llvm::Triple::NoSubArch || + Arch.getSubArch() == TT.getSubArch()) && + ((TT.getArch() == llvm::Triple::thumb && + Arch.getArch() == llvm::Triple::arm) || + (TT.getArch() == llvm::Triple::thumbeb && + Arch.getArch() == llvm::Triple::armeb))) + return true; + } + // Check the parsed arch when it has no sub arch to allow Clang to + // match thumb to thumbv7 but to prohibit matching thumbv6 to thumbv7. + return (Arch.getSubArch() == llvm::Triple::NoSubArch || + Arch.getSubArch() == TT.getSubArch()) && + Arch.getArch() == TT.getArch(); + } + + /// Implements the __is_target_vendor builtin macro. + static bool isTargetVendor(const TargetInfo &TI, const IdentifierInfo *II) { + StringRef VendorName = TI.getTriple().getVendorName(); + if (VendorName.empty()) + VendorName = "unknown"; + return VendorName.equals_insensitive(II->getName()); + } + + /// Implements the __is_target_os builtin macro. + static bool isTargetOS(const TargetInfo &TI, const IdentifierInfo *II) { + std::string OSName = + (llvm::Twine("unknown-unknown-") + II->getName().lower()).str(); + llvm::Triple OS(OSName); + if (OS.getOS() == llvm::Triple::Darwin) { + // Darwin matches macos, ios, etc. + return TI.getTriple().isOSDarwin(); + } + return TI.getTriple().getOS() == OS.getOS(); + } + + /// Implements the __is_target_environment builtin macro. + static bool isTargetEnvironment(const TargetInfo &TI, + const IdentifierInfo *II) { + std::string EnvName = (llvm::Twine("---") + II->getName().lower()).str(); + llvm::Triple Env(EnvName); + // The unknown environment is matched only if + // '__is_target_environment(unknown)' is used. + if (Env.getEnvironment() == llvm::Triple::UnknownEnvironment && + EnvName != "---unknown") + return false; + return TI.getTriple().getEnvironment() == Env.getEnvironment(); + } + + /// Implements the __is_target_variant_os builtin macro. + static bool isTargetVariantOS(const TargetInfo &TI, const IdentifierInfo *II) { + if (TI.getTriple().isOSDarwin()) { + const llvm::Triple *VariantTriple = TI.getDarwinTargetVariantTriple(); + if (!VariantTriple) + return false; + + std::string OSName = + (llvm::Twine("unknown-unknown-") + II->getName().lower()).str(); + llvm::Triple OS(OSName); + if (OS.getOS() == llvm::Triple::Darwin) { + // Darwin matches macos, ios, etc. + return VariantTriple->isOSDarwin(); + } + return VariantTriple->getOS() == OS.getOS(); + } + return false; + } + + /// Implements the __is_target_variant_environment builtin macro. + static bool isTargetVariantEnvironment(const TargetInfo &TI, + const IdentifierInfo *II) { + if (TI.getTriple().isOSDarwin()) { + const llvm::Triple *VariantTriple = TI.getDarwinTargetVariantTriple(); + if (!VariantTriple) + return false; + std::string EnvName = (llvm::Twine("---") + II->getName().lower()).str(); + llvm::Triple Env(EnvName); + return VariantTriple->getEnvironment() == Env.getEnvironment(); + } + return false; + } + + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded + /// as a builtin macro, handle it and return the next token as 'Tok'. + void Preprocessor::ExpandBuiltinMacro(Token &Tok) { + // Figure out which token this is. + IdentifierInfo *II = Tok.getIdentifierInfo(); + assert(II && "Can't be a macro without id info!"); + + // If this is an _Pragma or Microsoft __pragma directive, expand it, + // invoke the pragma handler, then lex the token after it. + if (II == Ident_Pragma) + return Handle_Pragma(Tok); + else if (II == Ident__pragma) // in non-MS mode this is null + return HandleMicrosoft__pragma(Tok); + + ++NumBuiltinMacroExpanded; + + SmallString<128> TmpBuffer; + llvm::raw_svector_ostream OS(TmpBuffer); + + // Set up the return result. + Tok.setIdentifierInfo(nullptr); + Tok.clearFlag(Token::NeedsCleaning); + bool IsAtStartOfLine = Tok.isAtStartOfLine(); + bool HasLeadingSpace = Tok.hasLeadingSpace(); + + if (II == Ident__LINE__) { + // C99 6.10.8: "__LINE__: The presumed line number (within the current + // source file) of the current source line (an integer constant)". This can + // be affected by #line. + SourceLocation Loc = Tok.getLocation(); + + // Advance to the location of the first _, this might not be the first byte + // of the token if it starts with an escaped newline. + Loc = AdvanceToTokenCharacter(Loc, 0); + + // One wrinkle here is that GCC expands __LINE__ to location of the *end* of + // a macro expansion. This doesn't matter for object-like macros, but + // can matter for a function-like macro that expands to contain __LINE__. + // Skip down through expansion points until we find a file loc for the + // end of the expansion history. + Loc = SourceMgr.getExpansionRange(Loc).getEnd(); + PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); + + // __LINE__ expands to a simple numeric value. + OS << (PLoc.isValid()? PLoc.getLine() : 1); + Tok.setKind(tok::numeric_constant); + } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__ || + II == Ident__FILE_NAME__) { + // C99 6.10.8: "__FILE__: The presumed name of the current source file (a + // character string literal)". This can be affected by #line. + PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); + + // __BASE_FILE__ is a GNU extension that returns the top of the presumed + // #include stack instead of the current file. + if (II == Ident__BASE_FILE__ && PLoc.isValid()) { + SourceLocation NextLoc = PLoc.getIncludeLoc(); + while (NextLoc.isValid()) { + PLoc = SourceMgr.getPresumedLoc(NextLoc); + if (PLoc.isInvalid()) + break; + + NextLoc = PLoc.getIncludeLoc(); + } + } + + // Escape this filename. Turn '\' -> '\\' '"' -> '\"' + SmallString<256> FN; + if (PLoc.isValid()) { + // __FILE_NAME__ is a Clang-specific extension that expands to the + // the last part of __FILE__. + if (II == Ident__FILE_NAME__) { + // Try to get the last path component, failing that return the original + // presumed location. + StringRef PLFileName = llvm::sys::path::filename(PLoc.getFilename()); + if (PLFileName != "") + FN += PLFileName; + else + FN += PLoc.getFilename(); + } else { + FN += PLoc.getFilename(); + } + processPathForFileMacro(FN, getLangOpts(), getTargetInfo()); + Lexer::Stringify(FN); + OS << '"' << FN << '"'; + } + Tok.setKind(tok::string_literal); + } else if (II == Ident__DATE__) { + Diag(Tok.getLocation(), diag::warn_pp_date_time); + if (!DATELoc.isValid()) + ComputeDATE_TIME(DATELoc, TIMELoc, *this); + Tok.setKind(tok::string_literal); + Tok.setLength(strlen("\"Mmm dd yyyy\"")); + Tok.setLocation(SourceMgr.createExpansionLoc(DATELoc, Tok.getLocation(), + Tok.getLocation(), + Tok.getLength())); + return; + } else if (II == Ident__TIME__) { + Diag(Tok.getLocation(), diag::warn_pp_date_time); + if (!TIMELoc.isValid()) + ComputeDATE_TIME(DATELoc, TIMELoc, *this); + Tok.setKind(tok::string_literal); + Tok.setLength(strlen("\"hh:mm:ss\"")); + Tok.setLocation(SourceMgr.createExpansionLoc(TIMELoc, Tok.getLocation(), + Tok.getLocation(), + Tok.getLength())); + return; + } else if (II == Ident__INCLUDE_LEVEL__) { + // Compute the presumed include depth of this token. This can be affected + // by GNU line markers. + unsigned Depth = 0; + + PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); + if (PLoc.isValid()) { + PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); + for (; PLoc.isValid(); ++Depth) + PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); + } + + // __INCLUDE_LEVEL__ expands to a simple numeric value. + OS << Depth; + Tok.setKind(tok::numeric_constant); + } else if (II == Ident__TIMESTAMP__) { + Diag(Tok.getLocation(), diag::warn_pp_date_time); + // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be + // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. + const char *Result; + if (getPreprocessorOpts().SourceDateEpoch) { + time_t TT = *getPreprocessorOpts().SourceDateEpoch; + std::tm *TM = std::gmtime(&TT); + Result = asctime(TM); + } else { + // Get the file that we are lexing out of. If we're currently lexing from + // a macro, dig into the include stack. + const FileEntry *CurFile = nullptr; + if (PreprocessorLexer *TheLexer = getCurrentFileLexer()) + CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); + if (CurFile) { + time_t TT = CurFile->getModificationTime(); + struct tm *TM = localtime(&TT); + Result = asctime(TM); + } else { + Result = "??? ??? ?? ??:??:?? ????\n"; + } + } + // Surround the string with " and strip the trailing newline. + OS << '"' << StringRef(Result).drop_back() << '"'; + Tok.setKind(tok::string_literal); + } else if (II == Ident__FLT_EVAL_METHOD__) { + // __FLT_EVAL_METHOD__ is set to the default value. +- if (getTUFPEvalMethod() == +- LangOptions::FPEvalMethodKind::FEM_Indeterminable) { +- // This is possible if `AllowFPReassoc` or `AllowReciprocal` is enabled. +- // These modes can be triggered via the command line option `-ffast-math` +- // or via a `pragam float_control`. +- // __FLT_EVAL_METHOD__ expands to -1. +- // The `minus` operator is the next token we read from the stream. +- auto Toks = std::make_unique(1); +- OS << "-"; +- Tok.setKind(tok::minus); +- // Push the token `1` to the stream. +- Token NumberToken; +- NumberToken.startToken(); +- NumberToken.setKind(tok::numeric_constant); +- NumberToken.setLiteralData("1"); +- NumberToken.setLength(1); +- Toks[0] = NumberToken; +- EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion*/ false, +- /*IsReinject*/ false); +- } else { +- OS << getTUFPEvalMethod(); +- // __FLT_EVAL_METHOD__ expands to a simple numeric value. +- Tok.setKind(tok::numeric_constant); +- if (getLastFPEvalPragmaLocation().isValid()) { +- // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is +- // altered by the pragma. +- Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); +- Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); +- } ++ OS << getTUFPEvalMethod(); ++ // __FLT_EVAL_METHOD__ expands to a simple numeric value. ++ Tok.setKind(tok::numeric_constant); ++ if (getLastFPEvalPragmaLocation().isValid()) { ++ // The program is ill-formed. The value of __FLT_EVAL_METHOD__ is altered ++ // by the pragma. ++ Diag(Tok, diag::err_illegal_use_of_flt_eval_macro); ++ Diag(getLastFPEvalPragmaLocation(), diag::note_pragma_entered_here); + } + } else if (II == Ident__COUNTER__) { + // __COUNTER__ expands to a simple numeric value. + OS << CounterValue++; + Tok.setKind(tok::numeric_constant); + } else if (II == Ident__has_feature) { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + return II && HasFeature(*this, II->getName()); + }); + } else if (II == Ident__has_extension) { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + return II && HasExtension(*this, II->getName()); + }); + } else if (II == Ident__has_builtin) { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + if (!II) + return false; + else if (II->getBuiltinID() != 0) { + switch (II->getBuiltinID()) { + case Builtin::BI__builtin_operator_new: + case Builtin::BI__builtin_operator_delete: + // denotes date of behavior change to support calling arbitrary + // usual allocation and deallocation functions. Required by libc++ + return 201802; + default: + return Builtin::evaluateRequiredTargetFeatures( + getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()), + getTargetInfo().getTargetOpts().FeatureMap); + } + return true; + } else if (II->getTokenID() != tok::identifier || + II->hasRevertedTokenIDToIdentifier()) { + // Treat all keywords that introduce a custom syntax of the form + // + // '__some_keyword' '(' [...] ')' + // + // as being "builtin functions", even if the syntax isn't a valid + // function call (for example, because the builtin takes a type + // argument). + if (II->getName().startswith("__builtin_") || + II->getName().startswith("__is_") || + II->getName().startswith("__has_")) + return true; + return llvm::StringSwitch(II->getName()) + .Case("__array_rank", true) + .Case("__array_extent", true) + .Case("__reference_binds_to_temporary", true) + #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true) + #include "clang/Basic/TransformTypeTraits.def" + .Default(false); + } else { + return llvm::StringSwitch(II->getName()) + // Report builtin templates as being builtins. + .Case("__make_integer_seq", getLangOpts().CPlusPlus) + .Case("__type_pack_element", getLangOpts().CPlusPlus) + // Likewise for some builtin preprocessor macros. + // FIXME: This is inconsistent; we usually suggest detecting + // builtin macros via #ifdef. Don't add more cases here. + .Case("__is_target_arch", true) + .Case("__is_target_vendor", true) + .Case("__is_target_os", true) + .Case("__is_target_environment", true) + .Case("__is_target_variant_os", true) + .Case("__is_target_variant_environment", true) + .Default(false); + } + }); + } else if (II == Ident__has_constexpr_builtin) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + if (!II) + return false; + unsigned BuiltinOp = II->getBuiltinID(); + return BuiltinOp != 0 && + this->getBuiltinInfo().isConstantEvaluated(BuiltinOp); + }); + } else if (II == Ident__is_identifier) { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, + [](Token &Tok, bool &HasLexedNextToken) -> int { + return Tok.is(tok::identifier); + }); + } else if (II == Ident__has_attribute) { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + return II ? hasAttribute(AttributeCommonInfo::Syntax::AS_GNU, nullptr, + II, getTargetInfo(), getLangOpts()) + : 0; + }); + } else if (II == Ident__has_declspec) { + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + if (II) { + const LangOptions &LangOpts = getLangOpts(); + return LangOpts.DeclSpecKeyword && + hasAttribute(AttributeCommonInfo::Syntax::AS_Declspec, nullptr, + II, getTargetInfo(), LangOpts); + } + + return false; + }); + } else if (II == Ident__has_cpp_attribute || + II == Ident__has_c_attribute) { + bool IsCXX = II == Ident__has_cpp_attribute; + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, true, + [&](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *ScopeII = nullptr; + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + if (!II) + return false; + + // It is possible to receive a scope token. Read the "::", if it is + // available, and the subsequent identifier. + LexUnexpandedToken(Tok); + if (Tok.isNot(tok::coloncolon)) + HasLexedNextToken = true; + else { + ScopeII = II; + // Lex an expanded token for the attribute name. + Lex(Tok); + II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_feature_check_malformed); + } + + AttributeCommonInfo::Syntax Syntax = + IsCXX ? AttributeCommonInfo::Syntax::AS_CXX11 + : AttributeCommonInfo::Syntax::AS_C2x; + return II ? hasAttribute(Syntax, ScopeII, II, getTargetInfo(), + getLangOpts()) + : 0; + }); + } else if (II == Ident__has_include || + II == Ident__has_include_next) { + // The argument to these two builtins should be a parenthesized + // file name string literal using angle brackets (<>) or + // double-quotes (""). + bool Value; + if (II == Ident__has_include) + Value = EvaluateHasInclude(Tok, II); + else + Value = EvaluateHasIncludeNext(Tok, II); + + if (Tok.isNot(tok::r_paren)) + return; + OS << (int)Value; + Tok.setKind(tok::numeric_constant); + } else if (II == Ident__has_warning) { + // The argument should be a parenthesized string literal. + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + std::string WarningName; + SourceLocation StrStartLoc = Tok.getLocation(); + + HasLexedNextToken = Tok.is(tok::string_literal); + if (!FinishLexStringLiteral(Tok, WarningName, "'__has_warning'", + /*AllowMacroExpansion=*/false)) + return false; + + // FIXME: Should we accept "-R..." flags here, or should that be + // handled by a separate __has_remark? + if (WarningName.size() < 3 || WarningName[0] != '-' || + WarningName[1] != 'W') { + Diag(StrStartLoc, diag::warn_has_warning_invalid_option); + return false; + } + + // Finally, check if the warning flags maps to a diagnostic group. + // We construct a SmallVector here to talk to getDiagnosticIDs(). + // Although we don't use the result, this isn't a hot path, and not + // worth special casing. + SmallVector Diags; + return !getDiagnostics().getDiagnosticIDs()-> + getDiagnosticsInGroup(diag::Flavor::WarningOrError, + WarningName.substr(2), Diags); + }); + } else if (II == Ident__building_module) { + // The argument to this builtin should be an identifier. The + // builtin evaluates to 1 when that identifier names the module we are + // currently building. + EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this, + diag::err_expected_id_building_module); + return getLangOpts().isCompilingModule() && II && + (II->getName() == getLangOpts().CurrentModule); + }); + } else if (II == Ident__MODULE__) { + // The current module as an identifier. + OS << getLangOpts().CurrentModule; + IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule); + Tok.setIdentifierInfo(ModuleII); + Tok.setKind(ModuleII->getTokenID()); + } else if (II == Ident__identifier) { + SourceLocation Loc = Tok.getLocation(); + + // We're expecting '__identifier' '(' identifier ')'. Try to recover + // if the parens are missing. + LexNonComment(Tok); + if (Tok.isNot(tok::l_paren)) { + // No '(', use end of last token. + Diag(getLocForEndOfToken(Loc), diag::err_pp_expected_after) + << II << tok::l_paren; + // If the next token isn't valid as our argument, we can't recover. + if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) + Tok.setKind(tok::identifier); + return; + } + + SourceLocation LParenLoc = Tok.getLocation(); + LexNonComment(Tok); + + if (!Tok.isAnnotation() && Tok.getIdentifierInfo()) + Tok.setKind(tok::identifier); + else if (Tok.is(tok::string_literal) && !Tok.hasUDSuffix()) { + StringLiteralParser Literal(Tok, *this); + if (Literal.hadError) + return; + + Tok.setIdentifierInfo(getIdentifierInfo(Literal.GetString())); + Tok.setKind(tok::identifier); + } else { + Diag(Tok.getLocation(), diag::err_pp_identifier_arg_not_identifier) + << Tok.getKind(); + // Don't walk past anything that's not a real token. + if (Tok.isOneOf(tok::eof, tok::eod) || Tok.isAnnotation()) + return; + } + + // Discard the ')', preserving 'Tok' as our result. + Token RParen; + LexNonComment(RParen); + if (RParen.isNot(tok::r_paren)) { + Diag(getLocForEndOfToken(Tok.getLocation()), diag::err_pp_expected_after) + << Tok.getKind() << tok::r_paren; + Diag(LParenLoc, diag::note_matching) << tok::l_paren; + } + return; + } else if (II == Ident__is_target_arch) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetArch(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_vendor) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetVendor(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_os) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetOS(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_environment) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetEnvironment(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_variant_os) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetVariantOS(getTargetInfo(), II); + }); + } else if (II == Ident__is_target_variant_environment) { + EvaluateFeatureLikeBuiltinMacro( + OS, Tok, II, *this, false, + [this](Token &Tok, bool &HasLexedNextToken) -> int { + IdentifierInfo *II = ExpectFeatureIdentifierInfo( + Tok, *this, diag::err_feature_check_malformed); + return II && isTargetVariantEnvironment(getTargetInfo(), II); + }); + } else { + llvm_unreachable("Unknown identifier!"); + } + CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); + Tok.setFlagValue(Token::StartOfLine, IsAtStartOfLine); + Tok.setFlagValue(Token::LeadingSpace, HasLeadingSpace); + } + + void Preprocessor::markMacroAsUsed(MacroInfo *MI) { + // If the 'used' status changed, and the macro requires 'unused' warning, + // remove its SourceLocation from the warn-for-unused-macro locations. + if (MI->isWarnIfUnused() && !MI->isUsed()) + WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); + MI->setIsUsed(true); + } + + void Preprocessor::processPathForFileMacro(SmallVectorImpl &Path, + const LangOptions &LangOpts, + const TargetInfo &TI) { + LangOpts.remapPathPrefix(Path); + if (LangOpts.UseTargetPathSeparator) { + if (TI.getTriple().isOSWindows()) + llvm::sys::path::remove_dots(Path, false, + llvm::sys::path::Style::windows_backslash); + else + llvm::sys::path::remove_dots(Path, false, llvm::sys::path::Style::posix); + } + } +diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp +index 27be7d611f59..8de78a13930e 100644 +--- a/clang/lib/Lex/Preprocessor.cpp ++++ b/clang/lib/Lex/Preprocessor.cpp +@@ -1,1577 +1,1572 @@ + //===- Preprocessor.cpp - C Language Family Preprocessor Implementation ---===// + // + // 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 Preprocessor interface. + // + //===----------------------------------------------------------------------===// + // + // Options to support: + // -H - Print the name of each header file used. + // -d[DNI] - Dump various things. + // -fworking-directory - #line's with preprocessor's working dir. + // -fpreprocessed + // -dependency-file,-M,-MM,-MF,-MG,-MP,-MT,-MQ,-MD,-MMD + // -W* + // -w + // + // Messages to emit: + // "Multiple include guards may be useful for:\n" + // + //===----------------------------------------------------------------------===// + + #include "clang/Lex/Preprocessor.h" + #include "clang/Basic/Builtins.h" + #include "clang/Basic/FileManager.h" + #include "clang/Basic/FileSystemStatCache.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/TargetInfo.h" + #include "clang/Lex/CodeCompletionHandler.h" + #include "clang/Lex/ExternalPreprocessorSource.h" + #include "clang/Lex/HeaderSearch.h" + #include "clang/Lex/LexDiagnostic.h" + #include "clang/Lex/Lexer.h" + #include "clang/Lex/LiteralSupport.h" + #include "clang/Lex/MacroArgs.h" + #include "clang/Lex/MacroInfo.h" + #include "clang/Lex/ModuleLoader.h" + #include "clang/Lex/Pragma.h" + #include "clang/Lex/PreprocessingRecord.h" + #include "clang/Lex/PreprocessorLexer.h" + #include "clang/Lex/PreprocessorOptions.h" + #include "clang/Lex/ScratchBuffer.h" + #include "clang/Lex/Token.h" + #include "clang/Lex/TokenLexer.h" + #include "llvm/ADT/APInt.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/Capacity.h" + #include "llvm/Support/ErrorHandling.h" + #include "llvm/Support/MemoryBuffer.h" + #include "llvm/Support/raw_ostream.h" + #include + #include + #include + #include + #include + #include + #include + + using namespace clang; + + LLVM_INSTANTIATE_REGISTRY(PragmaHandlerRegistry) + + ExternalPreprocessorSource::~ExternalPreprocessorSource() = default; + + Preprocessor::Preprocessor(std::shared_ptr PPOpts, + DiagnosticsEngine &diags, LangOptions &opts, + SourceManager &SM, HeaderSearch &Headers, + ModuleLoader &TheModuleLoader, + IdentifierInfoLookup *IILookup, bool OwnsHeaders, + TranslationUnitKind TUKind) + : PPOpts(std::move(PPOpts)), Diags(&diags), LangOpts(opts), + FileMgr(Headers.getFileMgr()), SourceMgr(SM), + ScratchBuf(new ScratchBuffer(SourceMgr)), HeaderInfo(Headers), + TheModuleLoader(TheModuleLoader), ExternalSource(nullptr), + // As the language options may have not been loaded yet (when + // deserializing an ASTUnit), adding keywords to the identifier table is + // deferred to Preprocessor::Initialize(). + Identifiers(IILookup), PragmaHandlers(new PragmaNamespace(StringRef())), + TUKind(TUKind), SkipMainFilePreamble(0, true), + CurSubmoduleState(&NullSubmoduleState) { + OwnsHeaderSearch = OwnsHeaders; + + // Default to discarding comments. + KeepComments = false; + KeepMacroComments = false; + SuppressIncludeNotFoundError = false; + + // Macro expansion is enabled. + DisableMacroExpansion = false; + MacroExpansionInDirectivesOverride = false; + InMacroArgs = false; + ArgMacro = nullptr; + InMacroArgPreExpansion = false; + NumCachedTokenLexers = 0; + PragmasEnabled = true; + ParsingIfOrElifDirective = false; + PreprocessedOutput = false; + + // We haven't read anything from the external source. + ReadMacrosFromExternalSource = false; + + BuiltinInfo = std::make_unique(); + + // "Poison" __VA_ARGS__, __VA_OPT__ which can only appear in the expansion of + // a macro. They get unpoisoned where it is allowed. + (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); + SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use); + (Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned(); + SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use); + + // Initialize the pragma handlers. + RegisterBuiltinPragmas(); + + // Initialize builtin macros like __LINE__ and friends. + RegisterBuiltinMacros(); + + if(LangOpts.Borland) { + Ident__exception_info = getIdentifierInfo("_exception_info"); + Ident___exception_info = getIdentifierInfo("__exception_info"); + Ident_GetExceptionInfo = getIdentifierInfo("GetExceptionInformation"); + Ident__exception_code = getIdentifierInfo("_exception_code"); + Ident___exception_code = getIdentifierInfo("__exception_code"); + Ident_GetExceptionCode = getIdentifierInfo("GetExceptionCode"); + Ident__abnormal_termination = getIdentifierInfo("_abnormal_termination"); + Ident___abnormal_termination = getIdentifierInfo("__abnormal_termination"); + Ident_AbnormalTermination = getIdentifierInfo("AbnormalTermination"); + } else { + Ident__exception_info = Ident__exception_code = nullptr; + Ident__abnormal_termination = Ident___exception_info = nullptr; + Ident___exception_code = Ident___abnormal_termination = nullptr; + Ident_GetExceptionInfo = Ident_GetExceptionCode = nullptr; + Ident_AbnormalTermination = nullptr; + } + + // If using a PCH where a #pragma hdrstop is expected, start skipping tokens. + if (usingPCHWithPragmaHdrStop()) + SkippingUntilPragmaHdrStop = true; + + // If using a PCH with a through header, start skipping tokens. + if (!this->PPOpts->PCHThroughHeader.empty() && + !this->PPOpts->ImplicitPCHInclude.empty()) + SkippingUntilPCHThroughHeader = true; + + if (this->PPOpts->GeneratePreamble) + PreambleConditionalStack.startRecording(); + + MaxTokens = LangOpts.MaxTokens; + } + + Preprocessor::~Preprocessor() { + assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!"); + + IncludeMacroStack.clear(); + + // Free any cached macro expanders. + // This populates MacroArgCache, so all TokenLexers need to be destroyed + // before the code below that frees up the MacroArgCache list. + std::fill(TokenLexerCache, TokenLexerCache + NumCachedTokenLexers, nullptr); + CurTokenLexer.reset(); + + // Free any cached MacroArgs. + for (MacroArgs *ArgList = MacroArgCache; ArgList;) + ArgList = ArgList->deallocate(); + + // Delete the header search info, if we own it. + if (OwnsHeaderSearch) + delete &HeaderInfo; + } + + void Preprocessor::Initialize(const TargetInfo &Target, + const TargetInfo *AuxTarget) { + assert((!this->Target || this->Target == &Target) && + "Invalid override of target information"); + this->Target = &Target; + + assert((!this->AuxTarget || this->AuxTarget == AuxTarget) && + "Invalid override of aux target information."); + this->AuxTarget = AuxTarget; + + // Initialize information about built-ins. + BuiltinInfo->InitializeTarget(Target, AuxTarget); + HeaderInfo.setTarget(Target); + + // Populate the identifier table with info about keywords for the current language. + Identifiers.AddKeywords(LangOpts); + + // Initialize the __FTL_EVAL_METHOD__ macro to the TargetInfo. + setTUFPEvalMethod(getTargetInfo().getFPEvalMethod()); + + if (getLangOpts().getFPEvalMethod() == LangOptions::FEM_UnsetOnCommandLine) + // Use setting from TargetInfo. + setCurrentFPEvalMethod(SourceLocation(), Target.getFPEvalMethod()); + else + // Set initial value of __FLT_EVAL_METHOD__ from the command line. + setCurrentFPEvalMethod(SourceLocation(), getLangOpts().getFPEvalMethod()); +- // When `-ffast-math` option is enabled, it triggers several driver math +- // options to be enabled. Among those, only one the following two modes +- // affect the eval-method: reciprocal or reassociate. +- if (getLangOpts().AllowFPReassoc || getLangOpts().AllowRecip) +- setCurrentFPEvalMethod(SourceLocation(), LangOptions::FEM_Indeterminable); + } + + void Preprocessor::InitializeForModelFile() { + NumEnteredSourceFiles = 0; + + // Reset pragmas + PragmaHandlersBackup = std::move(PragmaHandlers); + PragmaHandlers = std::make_unique(StringRef()); + RegisterBuiltinPragmas(); + + // Reset PredefinesFileID + PredefinesFileID = FileID(); + } + + void Preprocessor::FinalizeForModelFile() { + NumEnteredSourceFiles = 1; + + PragmaHandlers = std::move(PragmaHandlersBackup); + } + + void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { + llvm::errs() << tok::getTokenName(Tok.getKind()); + + if (!Tok.isAnnotation()) + llvm::errs() << " '" << getSpelling(Tok) << "'"; + + if (!DumpFlags) return; + + llvm::errs() << "\t"; + if (Tok.isAtStartOfLine()) + llvm::errs() << " [StartOfLine]"; + if (Tok.hasLeadingSpace()) + llvm::errs() << " [LeadingSpace]"; + if (Tok.isExpandDisabled()) + llvm::errs() << " [ExpandDisabled]"; + if (Tok.needsCleaning()) { + const char *Start = SourceMgr.getCharacterData(Tok.getLocation()); + llvm::errs() << " [UnClean='" << StringRef(Start, Tok.getLength()) + << "']"; + } + + llvm::errs() << "\tLoc=<"; + DumpLocation(Tok.getLocation()); + llvm::errs() << ">"; + } + + void Preprocessor::DumpLocation(SourceLocation Loc) const { + Loc.print(llvm::errs(), SourceMgr); + } + + void Preprocessor::DumpMacro(const MacroInfo &MI) const { + llvm::errs() << "MACRO: "; + for (unsigned i = 0, e = MI.getNumTokens(); i != e; ++i) { + DumpToken(MI.getReplacementToken(i)); + llvm::errs() << " "; + } + llvm::errs() << "\n"; + } + + void Preprocessor::PrintStats() { + llvm::errs() << "\n*** Preprocessor Stats:\n"; + llvm::errs() << NumDirectives << " directives found:\n"; + llvm::errs() << " " << NumDefined << " #define.\n"; + llvm::errs() << " " << NumUndefined << " #undef.\n"; + llvm::errs() << " #include/#include_next/#import:\n"; + llvm::errs() << " " << NumEnteredSourceFiles << " source files entered.\n"; + llvm::errs() << " " << MaxIncludeStackDepth << " max include stack depth\n"; + llvm::errs() << " " << NumIf << " #if/#ifndef/#ifdef.\n"; + llvm::errs() << " " << NumElse << " #else/#elif/#elifdef/#elifndef.\n"; + llvm::errs() << " " << NumEndif << " #endif.\n"; + llvm::errs() << " " << NumPragma << " #pragma.\n"; + llvm::errs() << NumSkipped << " #if/#ifndef#ifdef regions skipped\n"; + + llvm::errs() << NumMacroExpanded << "/" << NumFnMacroExpanded << "/" + << NumBuiltinMacroExpanded << " obj/fn/builtin macros expanded, " + << NumFastMacroExpanded << " on the fast path.\n"; + llvm::errs() << (NumFastTokenPaste+NumTokenPaste) + << " token paste (##) operations performed, " + << NumFastTokenPaste << " on the fast path.\n"; + + llvm::errs() << "\nPreprocessor Memory: " << getTotalMemory() << "B total"; + + llvm::errs() << "\n BumpPtr: " << BP.getTotalMemory(); + llvm::errs() << "\n Macro Expanded Tokens: " + << llvm::capacity_in_bytes(MacroExpandedTokens); + llvm::errs() << "\n Predefines Buffer: " << Predefines.capacity(); + // FIXME: List information for all submodules. + llvm::errs() << "\n Macros: " + << llvm::capacity_in_bytes(CurSubmoduleState->Macros); + llvm::errs() << "\n #pragma push_macro Info: " + << llvm::capacity_in_bytes(PragmaPushMacroInfo); + llvm::errs() << "\n Poison Reasons: " + << llvm::capacity_in_bytes(PoisonReasons); + llvm::errs() << "\n Comment Handlers: " + << llvm::capacity_in_bytes(CommentHandlers) << "\n"; + } + + Preprocessor::macro_iterator + Preprocessor::macro_begin(bool IncludeExternalMacros) const { + if (IncludeExternalMacros && ExternalSource && + !ReadMacrosFromExternalSource) { + ReadMacrosFromExternalSource = true; + ExternalSource->ReadDefinedMacros(); + } + + // Make sure we cover all macros in visible modules. + for (const ModuleMacro &Macro : ModuleMacros) + CurSubmoduleState->Macros.insert(std::make_pair(Macro.II, MacroState())); + + return CurSubmoduleState->Macros.begin(); + } + + size_t Preprocessor::getTotalMemory() const { + return BP.getTotalMemory() + + llvm::capacity_in_bytes(MacroExpandedTokens) + + Predefines.capacity() /* Predefines buffer. */ + // FIXME: Include sizes from all submodules, and include MacroInfo sizes, + // and ModuleMacros. + + llvm::capacity_in_bytes(CurSubmoduleState->Macros) + + llvm::capacity_in_bytes(PragmaPushMacroInfo) + + llvm::capacity_in_bytes(PoisonReasons) + + llvm::capacity_in_bytes(CommentHandlers); + } + + Preprocessor::macro_iterator + Preprocessor::macro_end(bool IncludeExternalMacros) const { + if (IncludeExternalMacros && ExternalSource && + !ReadMacrosFromExternalSource) { + ReadMacrosFromExternalSource = true; + ExternalSource->ReadDefinedMacros(); + } + + return CurSubmoduleState->Macros.end(); + } + + /// Compares macro tokens with a specified token value sequence. + static bool MacroDefinitionEquals(const MacroInfo *MI, + ArrayRef Tokens) { + return Tokens.size() == MI->getNumTokens() && + std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin()); + } + + StringRef Preprocessor::getLastMacroWithSpelling( + SourceLocation Loc, + ArrayRef Tokens) const { + SourceLocation BestLocation; + StringRef BestSpelling; + for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end(); + I != E; ++I) { + const MacroDirective::DefInfo + Def = I->second.findDirectiveAtLoc(Loc, SourceMgr); + if (!Def || !Def.getMacroInfo()) + continue; + if (!Def.getMacroInfo()->isObjectLike()) + continue; + if (!MacroDefinitionEquals(Def.getMacroInfo(), Tokens)) + continue; + SourceLocation Location = Def.getLocation(); + // Choose the macro defined latest. + if (BestLocation.isInvalid() || + (Location.isValid() && + SourceMgr.isBeforeInTranslationUnit(BestLocation, Location))) { + BestLocation = Location; + BestSpelling = I->first->getName(); + } + } + return BestSpelling; + } + + void Preprocessor::recomputeCurLexerKind() { + if (CurLexer) + CurLexerKind = CurLexer->isDependencyDirectivesLexer() + ? CLK_DependencyDirectivesLexer + : CLK_Lexer; + else if (CurTokenLexer) + CurLexerKind = CLK_TokenLexer; + else + CurLexerKind = CLK_CachingLexer; + } + + bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, + unsigned CompleteLine, + unsigned CompleteColumn) { + assert(File); + assert(CompleteLine && CompleteColumn && "Starts from 1:1"); + assert(!CodeCompletionFile && "Already set"); + + // Load the actual file's contents. + std::optional Buffer = + SourceMgr.getMemoryBufferForFileOrNone(File); + if (!Buffer) + return true; + + // Find the byte position of the truncation point. + const char *Position = Buffer->getBufferStart(); + for (unsigned Line = 1; Line < CompleteLine; ++Line) { + for (; *Position; ++Position) { + if (*Position != '\r' && *Position != '\n') + continue; + + // Eat \r\n or \n\r as a single line. + if ((Position[1] == '\r' || Position[1] == '\n') && + Position[0] != Position[1]) + ++Position; + ++Position; + break; + } + } + + Position += CompleteColumn - 1; + + // If pointing inside the preamble, adjust the position at the beginning of + // the file after the preamble. + if (SkipMainFilePreamble.first && + SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()) == File) { + if (Position - Buffer->getBufferStart() < SkipMainFilePreamble.first) + Position = Buffer->getBufferStart() + SkipMainFilePreamble.first; + } + + if (Position > Buffer->getBufferEnd()) + Position = Buffer->getBufferEnd(); + + CodeCompletionFile = File; + CodeCompletionOffset = Position - Buffer->getBufferStart(); + + auto NewBuffer = llvm::WritableMemoryBuffer::getNewUninitMemBuffer( + Buffer->getBufferSize() + 1, Buffer->getBufferIdentifier()); + char *NewBuf = NewBuffer->getBufferStart(); + char *NewPos = std::copy(Buffer->getBufferStart(), Position, NewBuf); + *NewPos = '\0'; + std::copy(Position, Buffer->getBufferEnd(), NewPos+1); + SourceMgr.overrideFileContents(File, std::move(NewBuffer)); + + return false; + } + + void Preprocessor::CodeCompleteIncludedFile(llvm::StringRef Dir, + bool IsAngled) { + setCodeCompletionReached(); + if (CodeComplete) + CodeComplete->CodeCompleteIncludedFile(Dir, IsAngled); + } + + void Preprocessor::CodeCompleteNaturalLanguage() { + setCodeCompletionReached(); + if (CodeComplete) + CodeComplete->CodeCompleteNaturalLanguage(); + } + + /// getSpelling - This method is used to get the spelling of a token into a + /// SmallVector. Note that the returned StringRef may not point to the + /// supplied buffer if a copy can be avoided. + StringRef Preprocessor::getSpelling(const Token &Tok, + SmallVectorImpl &Buffer, + bool *Invalid) const { + // NOTE: this has to be checked *before* testing for an IdentifierInfo. + if (Tok.isNot(tok::raw_identifier) && !Tok.hasUCN()) { + // Try the fast path. + if (const IdentifierInfo *II = Tok.getIdentifierInfo()) + return II->getName(); + } + + // Resize the buffer if we need to copy into it. + if (Tok.needsCleaning()) + Buffer.resize(Tok.getLength()); + + const char *Ptr = Buffer.data(); + unsigned Len = getSpelling(Tok, Ptr, Invalid); + return StringRef(Ptr, Len); + } + + /// CreateString - Plop the specified string into a scratch buffer and return a + /// location for it. If specified, the source location provides a source + /// location for the token. + void Preprocessor::CreateString(StringRef Str, Token &Tok, + SourceLocation ExpansionLocStart, + SourceLocation ExpansionLocEnd) { + Tok.setLength(Str.size()); + + const char *DestPtr; + SourceLocation Loc = ScratchBuf->getToken(Str.data(), Str.size(), DestPtr); + + if (ExpansionLocStart.isValid()) + Loc = SourceMgr.createExpansionLoc(Loc, ExpansionLocStart, + ExpansionLocEnd, Str.size()); + Tok.setLocation(Loc); + + // If this is a raw identifier or a literal token, set the pointer data. + if (Tok.is(tok::raw_identifier)) + Tok.setRawIdentifierData(DestPtr); + else if (Tok.isLiteral()) + Tok.setLiteralData(DestPtr); + } + + SourceLocation Preprocessor::SplitToken(SourceLocation Loc, unsigned Length) { + auto &SM = getSourceManager(); + SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); + std::pair LocInfo = SM.getDecomposedLoc(SpellingLoc); + bool Invalid = false; + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return SourceLocation(); + + // FIXME: We could consider re-using spelling for tokens we see repeatedly. + const char *DestPtr; + SourceLocation Spelling = + ScratchBuf->getToken(Buffer.data() + LocInfo.second, Length, DestPtr); + return SM.createTokenSplitLoc(Spelling, Loc, Loc.getLocWithOffset(Length)); + } + + Module *Preprocessor::getCurrentModule() { + if (!getLangOpts().isCompilingModule()) + return nullptr; + + return getHeaderSearchInfo().lookupModule(getLangOpts().CurrentModule); + } + + Module *Preprocessor::getCurrentModuleImplementation() { + if (!getLangOpts().isCompilingModuleImplementation()) + return nullptr; + + return getHeaderSearchInfo().lookupModule(getLangOpts().ModuleName); + } + + //===----------------------------------------------------------------------===// + // Preprocessor Initialization Methods + //===----------------------------------------------------------------------===// + + /// EnterMainSourceFile - Enter the specified FileID as the main source file, + /// which implicitly adds the builtin defines etc. + void Preprocessor::EnterMainSourceFile() { + // We do not allow the preprocessor to reenter the main file. Doing so will + // cause FileID's to accumulate information from both runs (e.g. #line + // information) and predefined macros aren't guaranteed to be set properly. + assert(NumEnteredSourceFiles == 0 && "Cannot reenter the main file!"); + FileID MainFileID = SourceMgr.getMainFileID(); + + // If MainFileID is loaded it means we loaded an AST file, no need to enter + // a main file. + if (!SourceMgr.isLoadedFileID(MainFileID)) { + // Enter the main file source buffer. + EnterSourceFile(MainFileID, nullptr, SourceLocation()); + + // If we've been asked to skip bytes in the main file (e.g., as part of a + // precompiled preamble), do so now. + if (SkipMainFilePreamble.first > 0) + CurLexer->SetByteOffset(SkipMainFilePreamble.first, + SkipMainFilePreamble.second); + + // Tell the header info that the main file was entered. If the file is later + // #imported, it won't be re-entered. + if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) + markIncluded(FE); + } + + // Preprocess Predefines to populate the initial preprocessor state. + std::unique_ptr SB = + llvm::MemoryBuffer::getMemBufferCopy(Predefines, ""); + assert(SB && "Cannot create predefined source buffer"); + FileID FID = SourceMgr.createFileID(std::move(SB)); + assert(FID.isValid() && "Could not create FileID for predefines?"); + setPredefinesFileID(FID); + + // Start parsing the predefines. + EnterSourceFile(FID, nullptr, SourceLocation()); + + if (!PPOpts->PCHThroughHeader.empty()) { + // Lookup and save the FileID for the through header. If it isn't found + // in the search path, it's a fatal error. + OptionalFileEntryRef File = LookupFile( + SourceLocation(), PPOpts->PCHThroughHeader, + /*isAngled=*/false, /*FromDir=*/nullptr, /*FromFile=*/nullptr, + /*CurDir=*/nullptr, /*SearchPath=*/nullptr, /*RelativePath=*/nullptr, + /*SuggestedModule=*/nullptr, /*IsMapped=*/nullptr, + /*IsFrameworkFound=*/nullptr); + if (!File) { + Diag(SourceLocation(), diag::err_pp_through_header_not_found) + << PPOpts->PCHThroughHeader; + return; + } + setPCHThroughHeaderFileID( + SourceMgr.createFileID(*File, SourceLocation(), SrcMgr::C_User)); + } + + // Skip tokens from the Predefines and if needed the main file. + if ((usingPCHWithThroughHeader() && SkippingUntilPCHThroughHeader) || + (usingPCHWithPragmaHdrStop() && SkippingUntilPragmaHdrStop)) + SkipTokensWhileUsingPCH(); + } + + void Preprocessor::setPCHThroughHeaderFileID(FileID FID) { + assert(PCHThroughHeaderFileID.isInvalid() && + "PCHThroughHeaderFileID already set!"); + PCHThroughHeaderFileID = FID; + } + + bool Preprocessor::isPCHThroughHeader(const FileEntry *FE) { + assert(PCHThroughHeaderFileID.isValid() && + "Invalid PCH through header FileID"); + return FE == SourceMgr.getFileEntryForID(PCHThroughHeaderFileID); + } + + bool Preprocessor::creatingPCHWithThroughHeader() { + return TUKind == TU_Prefix && !PPOpts->PCHThroughHeader.empty() && + PCHThroughHeaderFileID.isValid(); + } + + bool Preprocessor::usingPCHWithThroughHeader() { + return TUKind != TU_Prefix && !PPOpts->PCHThroughHeader.empty() && + PCHThroughHeaderFileID.isValid(); + } + + bool Preprocessor::creatingPCHWithPragmaHdrStop() { + return TUKind == TU_Prefix && PPOpts->PCHWithHdrStop; + } + + bool Preprocessor::usingPCHWithPragmaHdrStop() { + return TUKind != TU_Prefix && PPOpts->PCHWithHdrStop; + } + + /// Skip tokens until after the #include of the through header or + /// until after a #pragma hdrstop is seen. Tokens in the predefines file + /// and the main file may be skipped. If the end of the predefines file + /// is reached, skipping continues into the main file. If the end of the + /// main file is reached, it's a fatal error. + void Preprocessor::SkipTokensWhileUsingPCH() { + bool ReachedMainFileEOF = false; + bool UsingPCHThroughHeader = SkippingUntilPCHThroughHeader; + bool UsingPragmaHdrStop = SkippingUntilPragmaHdrStop; + Token Tok; + while (true) { + bool InPredefines = + (CurLexer && CurLexer->getFileID() == getPredefinesFileID()); + switch (CurLexerKind) { + case CLK_Lexer: + CurLexer->Lex(Tok); + break; + case CLK_TokenLexer: + CurTokenLexer->Lex(Tok); + break; + case CLK_CachingLexer: + CachingLex(Tok); + break; + case CLK_DependencyDirectivesLexer: + CurLexer->LexDependencyDirectiveToken(Tok); + break; + case CLK_LexAfterModuleImport: + LexAfterModuleImport(Tok); + break; + } + if (Tok.is(tok::eof) && !InPredefines) { + ReachedMainFileEOF = true; + break; + } + if (UsingPCHThroughHeader && !SkippingUntilPCHThroughHeader) + break; + if (UsingPragmaHdrStop && !SkippingUntilPragmaHdrStop) + break; + } + if (ReachedMainFileEOF) { + if (UsingPCHThroughHeader) + Diag(SourceLocation(), diag::err_pp_through_header_not_seen) + << PPOpts->PCHThroughHeader << 1; + else if (!PPOpts->PCHWithHdrStopCreate) + Diag(SourceLocation(), diag::err_pp_pragma_hdrstop_not_seen); + } + } + + void Preprocessor::replayPreambleConditionalStack() { + // Restore the conditional stack from the preamble, if there is one. + if (PreambleConditionalStack.isReplaying()) { + assert(CurPPLexer && + "CurPPLexer is null when calling replayPreambleConditionalStack."); + CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack()); + PreambleConditionalStack.doneReplaying(); + if (PreambleConditionalStack.reachedEOFWhileSkipping()) + SkipExcludedConditionalBlock( + PreambleConditionalStack.SkipInfo->HashTokenLoc, + PreambleConditionalStack.SkipInfo->IfTokenLoc, + PreambleConditionalStack.SkipInfo->FoundNonSkipPortion, + PreambleConditionalStack.SkipInfo->FoundElse, + PreambleConditionalStack.SkipInfo->ElseLoc); + } + } + + void Preprocessor::EndSourceFile() { + // Notify the client that we reached the end of the source file. + if (Callbacks) + Callbacks->EndOfMainFile(); + } + + //===----------------------------------------------------------------------===// + // Lexer Event Handling. + //===----------------------------------------------------------------------===// + + /// LookUpIdentifierInfo - Given a tok::raw_identifier token, look up the + /// identifier information for the token and install it into the token, + /// updating the token kind accordingly. + IdentifierInfo *Preprocessor::LookUpIdentifierInfo(Token &Identifier) const { + assert(!Identifier.getRawIdentifier().empty() && "No raw identifier data!"); + + // Look up this token, see if it is a macro, or if it is a language keyword. + IdentifierInfo *II; + if (!Identifier.needsCleaning() && !Identifier.hasUCN()) { + // No cleaning needed, just use the characters from the lexed buffer. + II = getIdentifierInfo(Identifier.getRawIdentifier()); + } else { + // Cleaning needed, alloca a buffer, clean into it, then use the buffer. + SmallString<64> IdentifierBuffer; + StringRef CleanedStr = getSpelling(Identifier, IdentifierBuffer); + + if (Identifier.hasUCN()) { + SmallString<64> UCNIdentifierBuffer; + expandUCNs(UCNIdentifierBuffer, CleanedStr); + II = getIdentifierInfo(UCNIdentifierBuffer); + } else { + II = getIdentifierInfo(CleanedStr); + } + } + + // Update the token info (identifier info and appropriate token kind). + // FIXME: the raw_identifier may contain leading whitespace which is removed + // from the cleaned identifier token. The SourceLocation should be updated to + // refer to the non-whitespace character. For instance, the text "\\\nB" (a + // line continuation before 'B') is parsed as a single tok::raw_identifier and + // is cleaned to tok::identifier "B". After cleaning the token's length is + // still 3 and the SourceLocation refers to the location of the backslash. + Identifier.setIdentifierInfo(II); + Identifier.setKind(II->getTokenID()); + + return II; + } + + void Preprocessor::SetPoisonReason(IdentifierInfo *II, unsigned DiagID) { + PoisonReasons[II] = DiagID; + } + + void Preprocessor::PoisonSEHIdentifiers(bool Poison) { + assert(Ident__exception_code && Ident__exception_info); + assert(Ident___exception_code && Ident___exception_info); + Ident__exception_code->setIsPoisoned(Poison); + Ident___exception_code->setIsPoisoned(Poison); + Ident_GetExceptionCode->setIsPoisoned(Poison); + Ident__exception_info->setIsPoisoned(Poison); + Ident___exception_info->setIsPoisoned(Poison); + Ident_GetExceptionInfo->setIsPoisoned(Poison); + Ident__abnormal_termination->setIsPoisoned(Poison); + Ident___abnormal_termination->setIsPoisoned(Poison); + Ident_AbnormalTermination->setIsPoisoned(Poison); + } + + void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) { + assert(Identifier.getIdentifierInfo() && + "Can't handle identifiers without identifier info!"); + llvm::DenseMap::const_iterator it = + PoisonReasons.find(Identifier.getIdentifierInfo()); + if(it == PoisonReasons.end()) + Diag(Identifier, diag::err_pp_used_poisoned_id); + else + Diag(Identifier,it->second) << Identifier.getIdentifierInfo(); + } + + void Preprocessor::updateOutOfDateIdentifier(IdentifierInfo &II) const { + assert(II.isOutOfDate() && "not out of date"); + getExternalSource()->updateOutOfDateIdentifier(II); + } + + /// HandleIdentifier - This callback is invoked when the lexer reads an + /// identifier. This callback looks up the identifier in the map and/or + /// potentially macro expands it or turns it into a named token (like 'for'). + /// + /// Note that callers of this method are guarded by checking the + /// IdentifierInfo's 'isHandleIdentifierCase' bit. If this method changes, the + /// IdentifierInfo methods that compute these properties will need to change to + /// match. + bool Preprocessor::HandleIdentifier(Token &Identifier) { + assert(Identifier.getIdentifierInfo() && + "Can't handle identifiers without identifier info!"); + + IdentifierInfo &II = *Identifier.getIdentifierInfo(); + + // If the information about this identifier is out of date, update it from + // the external source. + // We have to treat __VA_ARGS__ in a special way, since it gets + // serialized with isPoisoned = true, but our preprocessor may have + // unpoisoned it if we're defining a C99 macro. + if (II.isOutOfDate()) { + bool CurrentIsPoisoned = false; + const bool IsSpecialVariadicMacro = + &II == Ident__VA_ARGS__ || &II == Ident__VA_OPT__; + if (IsSpecialVariadicMacro) + CurrentIsPoisoned = II.isPoisoned(); + + updateOutOfDateIdentifier(II); + Identifier.setKind(II.getTokenID()); + + if (IsSpecialVariadicMacro) + II.setIsPoisoned(CurrentIsPoisoned); + } + + // If this identifier was poisoned, and if it was not produced from a macro + // expansion, emit an error. + if (II.isPoisoned() && CurPPLexer) { + HandlePoisonedIdentifier(Identifier); + } + + // If this is a macro to be expanded, do it. + if (MacroDefinition MD = getMacroDefinition(&II)) { + auto *MI = MD.getMacroInfo(); + assert(MI && "macro definition with no macro info?"); + if (!DisableMacroExpansion) { + if (!Identifier.isExpandDisabled() && MI->isEnabled()) { + // C99 6.10.3p10: If the preprocessing token immediately after the + // macro name isn't a '(', this macro should not be expanded. + if (!MI->isFunctionLike() || isNextPPTokenLParen()) + return HandleMacroExpandedIdentifier(Identifier, MD); + } else { + // C99 6.10.3.4p2 says that a disabled macro may never again be + // expanded, even if it's in a context where it could be expanded in the + // future. + Identifier.setFlag(Token::DisableExpand); + if (MI->isObjectLike() || isNextPPTokenLParen()) + Diag(Identifier, diag::pp_disabled_macro_expansion); + } + } + } + + // If this identifier is a keyword in a newer Standard or proposed Standard, + // produce a warning. Don't warn if we're not considering macro expansion, + // since this identifier might be the name of a macro. + // FIXME: This warning is disabled in cases where it shouldn't be, like + // "#define constexpr constexpr", "int constexpr;" + if (II.isFutureCompatKeyword() && !DisableMacroExpansion) { + Diag(Identifier, getIdentifierTable().getFutureCompatDiagKind(II, getLangOpts())) + << II.getName(); + // Don't diagnose this keyword again in this translation unit. + II.setIsFutureCompatKeyword(false); + } + + // If this is an extension token, diagnose its use. + // We avoid diagnosing tokens that originate from macro definitions. + // FIXME: This warning is disabled in cases where it shouldn't be, + // like "#define TY typeof", "TY(1) x". + if (II.isExtensionToken() && !DisableMacroExpansion) + Diag(Identifier, diag::ext_token_used); + + // If this is the 'import' contextual keyword following an '@', note + // that the next token indicates a module name. + // + // Note that we do not treat 'import' as a contextual + // keyword when we're in a caching lexer, because caching lexers only get + // used in contexts where import declarations are disallowed. + // + // Likewise if this is the standard C++ import keyword. + if (((LastTokenWasAt && II.isModulesImport()) || + Identifier.is(tok::kw_import)) && + !InMacroArgs && !DisableMacroExpansion && + (getLangOpts().Modules || getLangOpts().DebuggerSupport) && + CurLexerKind != CLK_CachingLexer) { + ModuleImportLoc = Identifier.getLocation(); + NamedModuleImportPath.clear(); + IsAtImport = true; + ModuleImportExpectsIdentifier = true; + CurLexerKind = CLK_LexAfterModuleImport; + } + return true; + } + + void Preprocessor::Lex(Token &Result) { + ++LexLevel; + + // We loop here until a lex function returns a token; this avoids recursion. + bool ReturnedToken; + do { + switch (CurLexerKind) { + case CLK_Lexer: + ReturnedToken = CurLexer->Lex(Result); + break; + case CLK_TokenLexer: + ReturnedToken = CurTokenLexer->Lex(Result); + break; + case CLK_CachingLexer: + CachingLex(Result); + ReturnedToken = true; + break; + case CLK_DependencyDirectivesLexer: + ReturnedToken = CurLexer->LexDependencyDirectiveToken(Result); + break; + case CLK_LexAfterModuleImport: + ReturnedToken = LexAfterModuleImport(Result); + break; + } + } while (!ReturnedToken); + + if (Result.is(tok::unknown) && TheModuleLoader.HadFatalFailure) + return; + + if (Result.is(tok::code_completion) && Result.getIdentifierInfo()) { + // Remember the identifier before code completion token. + setCodeCompletionIdentifierInfo(Result.getIdentifierInfo()); + setCodeCompletionTokenRange(Result.getLocation(), Result.getEndLoc()); + // Set IdenfitierInfo to null to avoid confusing code that handles both + // identifiers and completion tokens. + Result.setIdentifierInfo(nullptr); + } + + // Update StdCXXImportSeqState to track our position within a C++20 import-seq + // if this token is being produced as a result of phase 4 of translation. + // Update TrackGMFState to decide if we are currently in a Global Module + // Fragment. GMF state updates should precede StdCXXImportSeq ones, since GMF state + // depends on the prevailing StdCXXImportSeq state in two cases. + if (getLangOpts().CPlusPlusModules && LexLevel == 1 && + !Result.getFlag(Token::IsReinjected)) { + switch (Result.getKind()) { + case tok::l_paren: case tok::l_square: case tok::l_brace: + StdCXXImportSeqState.handleOpenBracket(); + break; + case tok::r_paren: case tok::r_square: + StdCXXImportSeqState.handleCloseBracket(); + break; + case tok::r_brace: + StdCXXImportSeqState.handleCloseBrace(); + break; + // This token is injected to represent the translation of '#include "a.h"' + // into "import a.h;". Mimic the notional ';'. + case tok::annot_module_include: + case tok::semi: + TrackGMFState.handleSemi(); + StdCXXImportSeqState.handleSemi(); + ModuleDeclState.handleSemi(); + break; + case tok::header_name: + case tok::annot_header_unit: + StdCXXImportSeqState.handleHeaderName(); + break; + case tok::kw_export: + TrackGMFState.handleExport(); + StdCXXImportSeqState.handleExport(); + ModuleDeclState.handleExport(); + break; + case tok::colon: + ModuleDeclState.handleColon(); + break; + case tok::period: + ModuleDeclState.handlePeriod(); + break; + case tok::identifier: + if (Result.getIdentifierInfo()->isModulesImport()) { + TrackGMFState.handleImport(StdCXXImportSeqState.afterTopLevelSeq()); + StdCXXImportSeqState.handleImport(); + if (StdCXXImportSeqState.afterImportSeq()) { + ModuleImportLoc = Result.getLocation(); + NamedModuleImportPath.clear(); + IsAtImport = false; + ModuleImportExpectsIdentifier = true; + CurLexerKind = CLK_LexAfterModuleImport; + } + break; + } else if (Result.getIdentifierInfo() == getIdentifierInfo("module")) { + TrackGMFState.handleModule(StdCXXImportSeqState.afterTopLevelSeq()); + ModuleDeclState.handleModule(); + break; + } else { + ModuleDeclState.handleIdentifier(Result.getIdentifierInfo()); + if (ModuleDeclState.isModuleCandidate()) + break; + } + [[fallthrough]]; + default: + TrackGMFState.handleMisc(); + StdCXXImportSeqState.handleMisc(); + ModuleDeclState.handleMisc(); + break; + } + } + + LastTokenWasAt = Result.is(tok::at); + --LexLevel; + + if ((LexLevel == 0 || PreprocessToken) && + !Result.getFlag(Token::IsReinjected)) { + if (LexLevel == 0) + ++TokenCount; + if (OnToken) + OnToken(Result); + } + } + + /// Lex a header-name token (including one formed from header-name-tokens if + /// \p AllowConcatenation is \c true). + /// + /// \param FilenameTok Filled in with the next token. On success, this will + /// be either a header_name token. On failure, it will be whatever other + /// token was found instead. + /// \param AllowMacroExpansion If \c true, allow the header name to be formed + /// by macro expansion (concatenating tokens as necessary if the first + /// token is a '<'). + /// \return \c true if we reached EOD or EOF while looking for a > token in + /// a concatenated header name and diagnosed it. \c false otherwise. + bool Preprocessor::LexHeaderName(Token &FilenameTok, bool AllowMacroExpansion) { + // Lex using header-name tokenization rules if tokens are being lexed from + // a file. Just grab a token normally if we're in a macro expansion. + if (CurPPLexer) + CurPPLexer->LexIncludeFilename(FilenameTok); + else + Lex(FilenameTok); + + // This could be a file coming from a macro expansion. In this + // case, glue the tokens together into an angle_string_literal token. + SmallString<128> FilenameBuffer; + if (FilenameTok.is(tok::less) && AllowMacroExpansion) { + bool StartOfLine = FilenameTok.isAtStartOfLine(); + bool LeadingSpace = FilenameTok.hasLeadingSpace(); + bool LeadingEmptyMacro = FilenameTok.hasLeadingEmptyMacro(); + + SourceLocation Start = FilenameTok.getLocation(); + SourceLocation End; + FilenameBuffer.push_back('<'); + + // Consume tokens until we find a '>'. + // FIXME: A header-name could be formed starting or ending with an + // alternative token. It's not clear whether that's ill-formed in all + // cases. + while (FilenameTok.isNot(tok::greater)) { + Lex(FilenameTok); + if (FilenameTok.isOneOf(tok::eod, tok::eof)) { + Diag(FilenameTok.getLocation(), diag::err_expected) << tok::greater; + Diag(Start, diag::note_matching) << tok::less; + return true; + } + + End = FilenameTok.getLocation(); + + // FIXME: Provide code completion for #includes. + if (FilenameTok.is(tok::code_completion)) { + setCodeCompletionReached(); + Lex(FilenameTok); + continue; + } + + // Append the spelling of this token to the buffer. If there was a space + // before it, add it now. + if (FilenameTok.hasLeadingSpace()) + FilenameBuffer.push_back(' '); + + // Get the spelling of the token, directly into FilenameBuffer if + // possible. + size_t PreAppendSize = FilenameBuffer.size(); + FilenameBuffer.resize(PreAppendSize + FilenameTok.getLength()); + + const char *BufPtr = &FilenameBuffer[PreAppendSize]; + unsigned ActualLen = getSpelling(FilenameTok, BufPtr); + + // If the token was spelled somewhere else, copy it into FilenameBuffer. + if (BufPtr != &FilenameBuffer[PreAppendSize]) + memcpy(&FilenameBuffer[PreAppendSize], BufPtr, ActualLen); + + // Resize FilenameBuffer to the correct size. + if (FilenameTok.getLength() != ActualLen) + FilenameBuffer.resize(PreAppendSize + ActualLen); + } + + FilenameTok.startToken(); + FilenameTok.setKind(tok::header_name); + FilenameTok.setFlagValue(Token::StartOfLine, StartOfLine); + FilenameTok.setFlagValue(Token::LeadingSpace, LeadingSpace); + FilenameTok.setFlagValue(Token::LeadingEmptyMacro, LeadingEmptyMacro); + CreateString(FilenameBuffer, FilenameTok, Start, End); + } else if (FilenameTok.is(tok::string_literal) && AllowMacroExpansion) { + // Convert a string-literal token of the form " h-char-sequence " + // (produced by macro expansion) into a header-name token. + // + // The rules for header-names don't quite match the rules for + // string-literals, but all the places where they differ result in + // undefined behavior, so we can and do treat them the same. + // + // A string-literal with a prefix or suffix is not translated into a + // header-name. This could theoretically be observable via the C++20 + // context-sensitive header-name formation rules. + StringRef Str = getSpelling(FilenameTok, FilenameBuffer); + if (Str.size() >= 2 && Str.front() == '"' && Str.back() == '"') + FilenameTok.setKind(tok::header_name); + } + + return false; + } + + /// Collect the tokens of a C++20 pp-import-suffix. + void Preprocessor::CollectPpImportSuffix(SmallVectorImpl &Toks) { + // FIXME: For error recovery, consider recognizing attribute syntax here + // and terminating / diagnosing a missing semicolon if we find anything + // else? (Can we leave that to the parser?) + unsigned BracketDepth = 0; + while (true) { + Toks.emplace_back(); + Lex(Toks.back()); + + switch (Toks.back().getKind()) { + case tok::l_paren: case tok::l_square: case tok::l_brace: + ++BracketDepth; + break; + + case tok::r_paren: case tok::r_square: case tok::r_brace: + if (BracketDepth == 0) + return; + --BracketDepth; + break; + + case tok::semi: + if (BracketDepth == 0) + return; + break; + + case tok::eof: + return; + + default: + break; + } + } + } + + + /// Lex a token following the 'import' contextual keyword. + /// + /// pp-import: [C++20] + /// import header-name pp-import-suffix[opt] ; + /// import header-name-tokens pp-import-suffix[opt] ; + /// [ObjC] @ import module-name ; + /// [Clang] import module-name ; + /// + /// header-name-tokens: + /// string-literal + /// < [any sequence of preprocessing-tokens other than >] > + /// + /// module-name: + /// module-name-qualifier[opt] identifier + /// + /// module-name-qualifier + /// module-name-qualifier[opt] identifier . + /// + /// We respond to a pp-import by importing macros from the named module. + bool Preprocessor::LexAfterModuleImport(Token &Result) { + // Figure out what kind of lexer we actually have. + recomputeCurLexerKind(); + + // Lex the next token. The header-name lexing rules are used at the start of + // a pp-import. + // + // For now, we only support header-name imports in C++20 mode. + // FIXME: Should we allow this in all language modes that support an import + // declaration as an extension? + if (NamedModuleImportPath.empty() && getLangOpts().CPlusPlusModules) { + if (LexHeaderName(Result)) + return true; + + if (Result.is(tok::colon) && ModuleDeclState.isNamedModule()) { + std::string Name = ModuleDeclState.getPrimaryName().str(); + Name += ":"; + NamedModuleImportPath.push_back( + {getIdentifierInfo(Name), Result.getLocation()}); + CurLexerKind = CLK_LexAfterModuleImport; + return true; + } + } else { + Lex(Result); + } + + // Allocate a holding buffer for a sequence of tokens and introduce it into + // the token stream. + auto EnterTokens = [this](ArrayRef Toks) { + auto ToksCopy = std::make_unique(Toks.size()); + std::copy(Toks.begin(), Toks.end(), ToksCopy.get()); + EnterTokenStream(std::move(ToksCopy), Toks.size(), + /*DisableMacroExpansion*/ true, /*IsReinject*/ false); + }; + + bool ImportingHeader = Result.is(tok::header_name); + // Check for a header-name. + SmallVector Suffix; + if (ImportingHeader) { + // Enter the header-name token into the token stream; a Lex action cannot + // both return a token and cache tokens (doing so would corrupt the token + // cache if the call to Lex comes from CachingLex / PeekAhead). + Suffix.push_back(Result); + + // Consume the pp-import-suffix and expand any macros in it now. We'll add + // it back into the token stream later. + CollectPpImportSuffix(Suffix); + if (Suffix.back().isNot(tok::semi)) { + // This is not a pp-import after all. + EnterTokens(Suffix); + return false; + } + + // C++2a [cpp.module]p1: + // The ';' preprocessing-token terminating a pp-import shall not have + // been produced by macro replacement. + SourceLocation SemiLoc = Suffix.back().getLocation(); + if (SemiLoc.isMacroID()) + Diag(SemiLoc, diag::err_header_import_semi_in_macro); + + // Reconstitute the import token. + Token ImportTok; + ImportTok.startToken(); + ImportTok.setKind(tok::kw_import); + ImportTok.setLocation(ModuleImportLoc); + ImportTok.setIdentifierInfo(getIdentifierInfo("import")); + ImportTok.setLength(6); + + auto Action = HandleHeaderIncludeOrImport( + /*HashLoc*/ SourceLocation(), ImportTok, Suffix.front(), SemiLoc); + switch (Action.Kind) { + case ImportAction::None: + break; + + case ImportAction::ModuleBegin: + // Let the parser know we're textually entering the module. + Suffix.emplace_back(); + Suffix.back().startToken(); + Suffix.back().setKind(tok::annot_module_begin); + Suffix.back().setLocation(SemiLoc); + Suffix.back().setAnnotationEndLoc(SemiLoc); + Suffix.back().setAnnotationValue(Action.ModuleForHeader); + [[fallthrough]]; + + case ImportAction::ModuleImport: + case ImportAction::HeaderUnitImport: + case ImportAction::SkippedModuleImport: + // We chose to import (or textually enter) the file. Convert the + // header-name token into a header unit annotation token. + Suffix[0].setKind(tok::annot_header_unit); + Suffix[0].setAnnotationEndLoc(Suffix[0].getLocation()); + Suffix[0].setAnnotationValue(Action.ModuleForHeader); + // FIXME: Call the moduleImport callback? + break; + case ImportAction::Failure: + assert(TheModuleLoader.HadFatalFailure && + "This should be an early exit only to a fatal error"); + Result.setKind(tok::eof); + CurLexer->cutOffLexing(); + EnterTokens(Suffix); + return true; + } + + EnterTokens(Suffix); + return false; + } + + // The token sequence + // + // import identifier (. identifier)* + // + // indicates a module import directive. We already saw the 'import' + // contextual keyword, so now we're looking for the identifiers. + if (ModuleImportExpectsIdentifier && Result.getKind() == tok::identifier) { + // We expected to see an identifier here, and we did; continue handling + // identifiers. + NamedModuleImportPath.push_back( + std::make_pair(Result.getIdentifierInfo(), Result.getLocation())); + ModuleImportExpectsIdentifier = false; + CurLexerKind = CLK_LexAfterModuleImport; + return true; + } + + // If we're expecting a '.' or a ';', and we got a '.', then wait until we + // see the next identifier. (We can also see a '[[' that begins an + // attribute-specifier-seq here under the Standard C++ Modules.) + if (!ModuleImportExpectsIdentifier && Result.getKind() == tok::period) { + ModuleImportExpectsIdentifier = true; + CurLexerKind = CLK_LexAfterModuleImport; + return true; + } + + // If we didn't recognize a module name at all, this is not a (valid) import. + if (NamedModuleImportPath.empty() || Result.is(tok::eof)) + return true; + + // Consume the pp-import-suffix and expand any macros in it now, if we're not + // at the semicolon already. + SourceLocation SemiLoc = Result.getLocation(); + if (Result.isNot(tok::semi)) { + Suffix.push_back(Result); + CollectPpImportSuffix(Suffix); + if (Suffix.back().isNot(tok::semi)) { + // This is not an import after all. + EnterTokens(Suffix); + return false; + } + SemiLoc = Suffix.back().getLocation(); + } + + // Under the standard C++ Modules, the dot is just part of the module name, + // and not a real hierarchy separator. Flatten such module names now. + // + // FIXME: Is this the right level to be performing this transformation? + std::string FlatModuleName; + if (getLangOpts().CPlusPlusModules) { + for (auto &Piece : NamedModuleImportPath) { + // If the FlatModuleName ends with colon, it implies it is a partition. + if (!FlatModuleName.empty() && FlatModuleName.back() != ':') + FlatModuleName += "."; + FlatModuleName += Piece.first->getName(); + } + SourceLocation FirstPathLoc = NamedModuleImportPath[0].second; + NamedModuleImportPath.clear(); + NamedModuleImportPath.push_back( + std::make_pair(getIdentifierInfo(FlatModuleName), FirstPathLoc)); + } + + Module *Imported = nullptr; + // We don't/shouldn't load the standard c++20 modules when preprocessing. + if (getLangOpts().Modules && !isInImportingCXXNamedModules()) { + Imported = TheModuleLoader.loadModule(ModuleImportLoc, + NamedModuleImportPath, + Module::Hidden, + /*IsInclusionDirective=*/false); + if (Imported) + makeModuleVisible(Imported, SemiLoc); + } + + if (Callbacks) + Callbacks->moduleImport(ModuleImportLoc, NamedModuleImportPath, Imported); + + if (!Suffix.empty()) { + EnterTokens(Suffix); + return false; + } + return true; + } + + void Preprocessor::makeModuleVisible(Module *M, SourceLocation Loc) { + CurSubmoduleState->VisibleModules.setVisible( + M, Loc, [](Module *) {}, + [&](ArrayRef Path, Module *Conflict, StringRef Message) { + // FIXME: Include the path in the diagnostic. + // FIXME: Include the import location for the conflicting module. + Diag(ModuleImportLoc, diag::warn_module_conflict) + << Path[0]->getFullModuleName() + << Conflict->getFullModuleName() + << Message; + }); + + // Add this module to the imports list of the currently-built submodule. + if (!BuildingSubmoduleStack.empty() && M != BuildingSubmoduleStack.back().M) + BuildingSubmoduleStack.back().M->Imports.insert(M); + } + + bool Preprocessor::FinishLexStringLiteral(Token &Result, std::string &String, + const char *DiagnosticTag, + bool AllowMacroExpansion) { + // We need at least one string literal. + if (Result.isNot(tok::string_literal)) { + Diag(Result, diag::err_expected_string_literal) + << /*Source='in...'*/0 << DiagnosticTag; + return false; + } + + // Lex string literal tokens, optionally with macro expansion. + SmallVector StrToks; + do { + StrToks.push_back(Result); + + if (Result.hasUDSuffix()) + Diag(Result, diag::err_invalid_string_udl); + + if (AllowMacroExpansion) + Lex(Result); + else + LexUnexpandedToken(Result); + } while (Result.is(tok::string_literal)); + + // Concatenate and parse the strings. + StringLiteralParser Literal(StrToks, *this); + assert(Literal.isOrdinary() && "Didn't allow wide strings in"); + + if (Literal.hadError) + return false; + + if (Literal.Pascal) { + Diag(StrToks[0].getLocation(), diag::err_expected_string_literal) + << /*Source='in...'*/0 << DiagnosticTag; + return false; + } + + String = std::string(Literal.GetString()); + return true; + } + + bool Preprocessor::parseSimpleIntegerLiteral(Token &Tok, uint64_t &Value) { + assert(Tok.is(tok::numeric_constant)); + SmallString<8> IntegerBuffer; + bool NumberInvalid = false; + StringRef Spelling = getSpelling(Tok, IntegerBuffer, &NumberInvalid); + if (NumberInvalid) + return false; + NumericLiteralParser Literal(Spelling, Tok.getLocation(), getSourceManager(), + getLangOpts(), getTargetInfo(), + getDiagnostics()); + if (Literal.hadError || !Literal.isIntegerLiteral() || Literal.hasUDSuffix()) + return false; + llvm::APInt APVal(64, 0); + if (Literal.GetIntegerValue(APVal)) + return false; + Lex(Tok); + Value = APVal.getLimitedValue(); + return true; + } + + void Preprocessor::addCommentHandler(CommentHandler *Handler) { + assert(Handler && "NULL comment handler"); + assert(!llvm::is_contained(CommentHandlers, Handler) && + "Comment handler already registered"); + CommentHandlers.push_back(Handler); + } + + void Preprocessor::removeCommentHandler(CommentHandler *Handler) { + std::vector::iterator Pos = + llvm::find(CommentHandlers, Handler); + assert(Pos != CommentHandlers.end() && "Comment handler not registered"); + CommentHandlers.erase(Pos); + } + + bool Preprocessor::HandleComment(Token &result, SourceRange Comment) { + bool AnyPendingTokens = false; + for (std::vector::iterator H = CommentHandlers.begin(), + HEnd = CommentHandlers.end(); + H != HEnd; ++H) { + if ((*H)->HandleComment(*this, Comment)) + AnyPendingTokens = true; + } + if (!AnyPendingTokens || getCommentRetentionState()) + return false; + Lex(result); + return true; + } + + void Preprocessor::emitMacroDeprecationWarning(const Token &Identifier) const { + const MacroAnnotations &A = + getMacroAnnotations(Identifier.getIdentifierInfo()); + assert(A.DeprecationInfo && + "Macro deprecation warning without recorded annotation!"); + const MacroAnnotationInfo &Info = *A.DeprecationInfo; + if (Info.Message.empty()) + Diag(Identifier, diag::warn_pragma_deprecated_macro_use) + << Identifier.getIdentifierInfo() << 0; + else + Diag(Identifier, diag::warn_pragma_deprecated_macro_use) + << Identifier.getIdentifierInfo() << 1 << Info.Message; + Diag(Info.Location, diag::note_pp_macro_annotation) << 0; + } + + void Preprocessor::emitRestrictExpansionWarning(const Token &Identifier) const { + const MacroAnnotations &A = + getMacroAnnotations(Identifier.getIdentifierInfo()); + assert(A.RestrictExpansionInfo && + "Macro restricted expansion warning without recorded annotation!"); + const MacroAnnotationInfo &Info = *A.RestrictExpansionInfo; + if (Info.Message.empty()) + Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use) + << Identifier.getIdentifierInfo() << 0; + else + Diag(Identifier, diag::warn_pragma_restrict_expansion_macro_use) + << Identifier.getIdentifierInfo() << 1 << Info.Message; + Diag(Info.Location, diag::note_pp_macro_annotation) << 1; + } + + void Preprocessor::emitFinalMacroWarning(const Token &Identifier, + bool IsUndef) const { + const MacroAnnotations &A = + getMacroAnnotations(Identifier.getIdentifierInfo()); + assert(A.FinalAnnotationLoc && + "Final macro warning without recorded annotation!"); + + Diag(Identifier, diag::warn_pragma_final_macro) + << Identifier.getIdentifierInfo() << (IsUndef ? 0 : 1); + Diag(*A.FinalAnnotationLoc, diag::note_pp_macro_annotation) << 2; + } + + bool Preprocessor::isSafeBufferOptOut(const SourceManager &SourceMgr, + const SourceLocation &Loc) const { + // Try to find a region in `SafeBufferOptOutMap` where `Loc` is in: + auto FirstRegionEndingAfterLoc = llvm::partition_point( + SafeBufferOptOutMap, + [&SourceMgr, + &Loc](const std::pair &Region) { + return SourceMgr.isBeforeInTranslationUnit(Region.second, Loc); + }); + + if (FirstRegionEndingAfterLoc != SafeBufferOptOutMap.end()) { + // To test if the start location of the found region precedes `Loc`: + return SourceMgr.isBeforeInTranslationUnit(FirstRegionEndingAfterLoc->first, + Loc); + } + // If we do not find a region whose end location passes `Loc`, we want to + // check if the current region is still open: + if (!SafeBufferOptOutMap.empty() && + SafeBufferOptOutMap.back().first == SafeBufferOptOutMap.back().second) + return SourceMgr.isBeforeInTranslationUnit(SafeBufferOptOutMap.back().first, + Loc); + return false; + } + + bool Preprocessor::enterOrExitSafeBufferOptOutRegion( + bool isEnter, const SourceLocation &Loc) { + if (isEnter) { + if (isPPInSafeBufferOptOutRegion()) + return true; // invalid enter action + InSafeBufferOptOutRegion = true; + CurrentSafeBufferOptOutStart = Loc; + + // To set the start location of a new region: + + if (!SafeBufferOptOutMap.empty()) { + [[maybe_unused]] auto *PrevRegion = &SafeBufferOptOutMap.back(); + assert(PrevRegion->first != PrevRegion->second && + "Shall not begin a safe buffer opt-out region before closing the " + "previous one."); + } + // If the start location equals to the end location, we call the region a + // open region or a unclosed region (i.e., end location has not been set + // yet). + SafeBufferOptOutMap.emplace_back(Loc, Loc); + } else { + if (!isPPInSafeBufferOptOutRegion()) + return true; // invalid enter action + InSafeBufferOptOutRegion = false; + + // To set the end location of the current open region: + + assert(!SafeBufferOptOutMap.empty() && + "Misordered safe buffer opt-out regions"); + auto *CurrRegion = &SafeBufferOptOutMap.back(); + assert(CurrRegion->first == CurrRegion->second && + "Set end location to a closed safe buffer opt-out region"); + CurrRegion->second = Loc; + } + return false; + } + + bool Preprocessor::isPPInSafeBufferOptOutRegion() { + return InSafeBufferOptOutRegion; + } + bool Preprocessor::isPPInSafeBufferOptOutRegion(SourceLocation &StartLoc) { + StartLoc = CurrentSafeBufferOptOutStart; + return InSafeBufferOptOutRegion; + } + + ModuleLoader::~ModuleLoader() = default; + + CommentHandler::~CommentHandler() = default; + + EmptylineHandler::~EmptylineHandler() = default; + + CodeCompletionHandler::~CodeCompletionHandler() = default; + + void Preprocessor::createPreprocessingRecord() { + if (Record) + return; + + Record = new PreprocessingRecord(getSourceManager()); + addPPCallbacks(std::unique_ptr(Record)); + } +diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp +index 42f582724564..3ea97f6aa8f2 100644 +--- a/clang/lib/Sema/SemaAttr.cpp ++++ b/clang/lib/Sema/SemaAttr.cpp +@@ -1,1464 +1,1447 @@ + //===--- SemaAttr.cpp - Semantic Analysis for Attributes ------------------===// + // + // 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 semantic analysis for non-trivial attributes and + // pragmas. + // + //===----------------------------------------------------------------------===// + + #include "clang/AST/ASTConsumer.h" + #include "clang/AST/Attr.h" + #include "clang/AST/Expr.h" + #include "clang/Basic/TargetInfo.h" + #include "clang/Lex/Preprocessor.h" + #include "clang/Sema/Lookup.h" + #include "clang/Sema/SemaInternal.h" + #include + using namespace clang; + + //===----------------------------------------------------------------------===// + // Pragma 'pack' and 'options align' + //===----------------------------------------------------------------------===// + + Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S, + StringRef SlotLabel, + bool ShouldAct) + : S(S), SlotLabel(SlotLabel), ShouldAct(ShouldAct) { + if (ShouldAct) { + S.VtorDispStack.SentinelAction(PSK_Push, SlotLabel); + S.DataSegStack.SentinelAction(PSK_Push, SlotLabel); + S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel); + S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel); + S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel); + S.StrictGuardStackCheckStack.SentinelAction(PSK_Push, SlotLabel); + } + } + + Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() { + if (ShouldAct) { + S.VtorDispStack.SentinelAction(PSK_Pop, SlotLabel); + S.DataSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.StrictGuardStackCheckStack.SentinelAction(PSK_Pop, SlotLabel); + } + } + + void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { + AlignPackInfo InfoVal = AlignPackStack.CurrentValue; + AlignPackInfo::Mode M = InfoVal.getAlignMode(); + bool IsPackSet = InfoVal.IsPackSet(); + bool IsXLPragma = getLangOpts().XLPragmaPack; + + // If we are not under mac68k/natural alignment mode and also there is no pack + // value, we don't need any attributes. + if (!IsPackSet && M != AlignPackInfo::Mac68k && M != AlignPackInfo::Natural) + return; + + if (M == AlignPackInfo::Mac68k && (IsXLPragma || InfoVal.IsAlignAttr())) { + RD->addAttr(AlignMac68kAttr::CreateImplicit(Context)); + } else if (IsPackSet) { + // Check to see if we need a max field alignment attribute. + RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit( + Context, InfoVal.getPackNumber() * 8)); + } + + if (IsXLPragma && M == AlignPackInfo::Natural) + RD->addAttr(AlignNaturalAttr::CreateImplicit(Context)); + + if (AlignPackIncludeStack.empty()) + return; + // The #pragma align/pack affected a record in an included file, so Clang + // should warn when that pragma was written in a file that included the + // included file. + for (auto &AlignPackedInclude : llvm::reverse(AlignPackIncludeStack)) { + if (AlignPackedInclude.CurrentPragmaLocation != + AlignPackStack.CurrentPragmaLocation) + break; + if (AlignPackedInclude.HasNonDefaultValue) + AlignPackedInclude.ShouldWarnOnInclude = true; + } + } + + void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { + if (MSStructPragmaOn) + RD->addAttr(MSStructAttr::CreateImplicit(Context)); + + // FIXME: We should merge AddAlignmentAttributesForRecord with + // AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes + // all active pragmas and applies them as attributes to class definitions. + if (VtorDispStack.CurrentValue != getLangOpts().getVtorDispMode()) + RD->addAttr(MSVtorDispAttr::CreateImplicit( + Context, unsigned(VtorDispStack.CurrentValue))); + } + + template + static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context, + CXXRecordDecl *Record) { + if (Record->hasAttr() || Record->hasAttr()) + return; + + for (Decl *Redecl : Record->redecls()) + Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr)); + } + + void Sema::inferGslPointerAttribute(NamedDecl *ND, + CXXRecordDecl *UnderlyingRecord) { + if (!UnderlyingRecord) + return; + + const auto *Parent = dyn_cast(ND->getDeclContext()); + if (!Parent) + return; + + static llvm::StringSet<> Containers{ + "array", + "basic_string", + "deque", + "forward_list", + "vector", + "list", + "map", + "multiset", + "multimap", + "priority_queue", + "queue", + "set", + "stack", + "unordered_set", + "unordered_map", + "unordered_multiset", + "unordered_multimap", + }; + + static llvm::StringSet<> Iterators{"iterator", "const_iterator", + "reverse_iterator", + "const_reverse_iterator"}; + + if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) && + Containers.count(Parent->getName())) + addGslOwnerPointerAttributeIfNotExisting(Context, + UnderlyingRecord); + } + + void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) { + + QualType Canonical = TD->getUnderlyingType().getCanonicalType(); + + CXXRecordDecl *RD = Canonical->getAsCXXRecordDecl(); + if (!RD) { + if (auto *TST = + dyn_cast(Canonical.getTypePtr())) { + + RD = dyn_cast_or_null( + TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl()); + } + } + + inferGslPointerAttribute(TD, RD); + } + + void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) { + static llvm::StringSet<> StdOwners{ + "any", + "array", + "basic_regex", + "basic_string", + "deque", + "forward_list", + "vector", + "list", + "map", + "multiset", + "multimap", + "optional", + "priority_queue", + "queue", + "set", + "stack", + "unique_ptr", + "unordered_set", + "unordered_map", + "unordered_multiset", + "unordered_multimap", + "variant", + }; + static llvm::StringSet<> StdPointers{ + "basic_string_view", + "reference_wrapper", + "regex_iterator", + }; + + if (!Record->getIdentifier()) + return; + + // Handle classes that directly appear in std namespace. + if (Record->isInStdNamespace()) { + if (Record->hasAttr() || Record->hasAttr()) + return; + + if (StdOwners.count(Record->getName())) + addGslOwnerPointerAttributeIfNotExisting(Context, Record); + else if (StdPointers.count(Record->getName())) + addGslOwnerPointerAttributeIfNotExisting(Context, Record); + + return; + } + + // Handle nested classes that could be a gsl::Pointer. + inferGslPointerAttribute(Record, Record); + } + + void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, + SourceLocation PragmaLoc) { + PragmaMsStackAction Action = Sema::PSK_Reset; + AlignPackInfo::Mode ModeVal = AlignPackInfo::Native; + + switch (Kind) { + // For most of the platforms we support, native and natural are the same. + // With XL, native is the same as power, natural means something else. + // + // FIXME: This is not true on Darwin/PPC. + case POAK_Native: + case POAK_Power: + Action = Sema::PSK_Push_Set; + break; + case POAK_Natural: + Action = Sema::PSK_Push_Set; + ModeVal = AlignPackInfo::Natural; + break; + + // Note that '#pragma options align=packed' is not equivalent to attribute + // packed, it has a different precedence relative to attribute aligned. + case POAK_Packed: + Action = Sema::PSK_Push_Set; + ModeVal = AlignPackInfo::Packed; + break; + + case POAK_Mac68k: + // Check if the target supports this. + if (!this->Context.getTargetInfo().hasAlignMac68kSupport()) { + Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported); + return; + } + Action = Sema::PSK_Push_Set; + ModeVal = AlignPackInfo::Mac68k; + break; + case POAK_Reset: + // Reset just pops the top of the stack, or resets the current alignment to + // default. + Action = Sema::PSK_Pop; + if (AlignPackStack.Stack.empty()) { + if (AlignPackStack.CurrentValue.getAlignMode() != AlignPackInfo::Native || + AlignPackStack.CurrentValue.IsPackAttr()) { + Action = Sema::PSK_Reset; + } else { + Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) + << "stack empty"; + return; + } + } + break; + } + + AlignPackInfo Info(ModeVal, getLangOpts().XLPragmaPack); + + AlignPackStack.Act(PragmaLoc, Action, StringRef(), Info); + } + + void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, + PragmaClangSectionAction Action, + PragmaClangSectionKind SecKind, + StringRef SecName) { + PragmaClangSection *CSec; + int SectionFlags = ASTContext::PSF_Read; + switch (SecKind) { + case PragmaClangSectionKind::PCSK_BSS: + CSec = &PragmaClangBSSSection; + SectionFlags |= ASTContext::PSF_Write | ASTContext::PSF_ZeroInit; + break; + case PragmaClangSectionKind::PCSK_Data: + CSec = &PragmaClangDataSection; + SectionFlags |= ASTContext::PSF_Write; + break; + case PragmaClangSectionKind::PCSK_Rodata: + CSec = &PragmaClangRodataSection; + break; + case PragmaClangSectionKind::PCSK_Relro: + CSec = &PragmaClangRelroSection; + break; + case PragmaClangSectionKind::PCSK_Text: + CSec = &PragmaClangTextSection; + SectionFlags |= ASTContext::PSF_Execute; + break; + default: + llvm_unreachable("invalid clang section kind"); + } + + if (Action == PragmaClangSectionAction::PCSA_Clear) { + CSec->Valid = false; + return; + } + + if (llvm::Error E = isValidSectionSpecifier(SecName)) { + Diag(PragmaLoc, diag::err_pragma_section_invalid_for_target) + << toString(std::move(E)); + CSec->Valid = false; + return; + } + + if (UnifySection(SecName, SectionFlags, PragmaLoc)) + return; + + CSec->Valid = true; + CSec->SectionName = std::string(SecName); + CSec->PragmaLocation = PragmaLoc; + } + + void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, + StringRef SlotLabel, Expr *alignment) { + bool IsXLPragma = getLangOpts().XLPragmaPack; + // XL pragma pack does not support identifier syntax. + if (IsXLPragma && !SlotLabel.empty()) { + Diag(PragmaLoc, diag::err_pragma_pack_identifer_not_supported); + return; + } + + const AlignPackInfo CurVal = AlignPackStack.CurrentValue; + Expr *Alignment = static_cast(alignment); + + // If specified then alignment must be a "small" power of two. + unsigned AlignmentVal = 0; + AlignPackInfo::Mode ModeVal = CurVal.getAlignMode(); + + if (Alignment) { + std::optional Val; + Val = Alignment->getIntegerConstantExpr(Context); + + // pack(0) is like pack(), which just works out since that is what + // we use 0 for in PackAttr. + if (Alignment->isTypeDependent() || !Val || + !(*Val == 0 || Val->isPowerOf2()) || Val->getZExtValue() > 16) { + Diag(PragmaLoc, diag::warn_pragma_pack_invalid_alignment); + return; // Ignore + } + + if (IsXLPragma && *Val == 0) { + // pack(0) does not work out with XL. + Diag(PragmaLoc, diag::err_pragma_pack_invalid_alignment); + return; // Ignore + } + + AlignmentVal = (unsigned)Val->getZExtValue(); + } + + if (Action == Sema::PSK_Show) { + // Show the current alignment, making sure to show the right value + // for the default. + // FIXME: This should come from the target. + AlignmentVal = CurVal.IsPackSet() ? CurVal.getPackNumber() : 8; + if (ModeVal == AlignPackInfo::Mac68k && + (IsXLPragma || CurVal.IsAlignAttr())) + Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k"; + else + Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; + } + + // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: + // "#pragma pack(pop, identifier, n) is undefined" + if (Action & Sema::PSK_Pop) { + if (Alignment && !SlotLabel.empty()) + Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifier_and_alignment); + if (AlignPackStack.Stack.empty()) { + assert(CurVal.getAlignMode() == AlignPackInfo::Native && + "Empty pack stack can only be at Native alignment mode."); + Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty"; + } + } + + AlignPackInfo Info(ModeVal, AlignmentVal, IsXLPragma); + + AlignPackStack.Act(PragmaLoc, Action, SlotLabel, Info); + } + + bool Sema::ConstantFoldAttrArgs(const AttributeCommonInfo &CI, + MutableArrayRef Args) { + llvm::SmallVector Notes; + for (unsigned Idx = 0; Idx < Args.size(); Idx++) { + Expr *&E = Args.begin()[Idx]; + assert(E && "error are handled before"); + if (E->isValueDependent() || E->isTypeDependent()) + continue; + + // FIXME: Use DefaultFunctionArrayLValueConversion() in place of the logic + // that adds implicit casts here. + if (E->getType()->isArrayType()) + E = ImpCastExprToType(E, Context.getPointerType(E->getType()), + clang::CK_ArrayToPointerDecay) + .get(); + if (E->getType()->isFunctionType()) + E = ImplicitCastExpr::Create(Context, + Context.getPointerType(E->getType()), + clang::CK_FunctionToPointerDecay, E, nullptr, + VK_PRValue, FPOptionsOverride()); + if (E->isLValue()) + E = ImplicitCastExpr::Create(Context, E->getType().getNonReferenceType(), + clang::CK_LValueToRValue, E, nullptr, + VK_PRValue, FPOptionsOverride()); + + Expr::EvalResult Eval; + Notes.clear(); + Eval.Diag = &Notes; + + bool Result = E->EvaluateAsConstantExpr(Eval, Context); + + /// Result means the expression can be folded to a constant. + /// Note.empty() means the expression is a valid constant expression in the + /// current language mode. + if (!Result || !Notes.empty()) { + Diag(E->getBeginLoc(), diag::err_attribute_argument_n_type) + << CI << (Idx + 1) << AANT_ArgumentConstantExpr; + for (auto &Note : Notes) + Diag(Note.first, Note.second); + return false; + } + assert(Eval.Val.hasValue()); + E = ConstantExpr::Create(Context, E, Eval.Val); + } + + return true; + } + + void Sema::DiagnoseNonDefaultPragmaAlignPack(PragmaAlignPackDiagnoseKind Kind, + SourceLocation IncludeLoc) { + if (Kind == PragmaAlignPackDiagnoseKind::NonDefaultStateAtInclude) { + SourceLocation PrevLocation = AlignPackStack.CurrentPragmaLocation; + // Warn about non-default alignment at #includes (without redundant + // warnings for the same directive in nested includes). + // The warning is delayed until the end of the file to avoid warnings + // for files that don't have any records that are affected by the modified + // alignment. + bool HasNonDefaultValue = + AlignPackStack.hasValue() && + (AlignPackIncludeStack.empty() || + AlignPackIncludeStack.back().CurrentPragmaLocation != PrevLocation); + AlignPackIncludeStack.push_back( + {AlignPackStack.CurrentValue, + AlignPackStack.hasValue() ? PrevLocation : SourceLocation(), + HasNonDefaultValue, /*ShouldWarnOnInclude*/ false}); + return; + } + + assert(Kind == PragmaAlignPackDiagnoseKind::ChangedStateAtExit && + "invalid kind"); + AlignPackIncludeState PrevAlignPackState = + AlignPackIncludeStack.pop_back_val(); + // FIXME: AlignPackStack may contain both #pragma align and #pragma pack + // information, diagnostics below might not be accurate if we have mixed + // pragmas. + if (PrevAlignPackState.ShouldWarnOnInclude) { + // Emit the delayed non-default alignment at #include warning. + Diag(IncludeLoc, diag::warn_pragma_pack_non_default_at_include); + Diag(PrevAlignPackState.CurrentPragmaLocation, diag::note_pragma_pack_here); + } + // Warn about modified alignment after #includes. + if (PrevAlignPackState.CurrentValue != AlignPackStack.CurrentValue) { + Diag(IncludeLoc, diag::warn_pragma_pack_modified_after_include); + Diag(AlignPackStack.CurrentPragmaLocation, diag::note_pragma_pack_here); + } + } + + void Sema::DiagnoseUnterminatedPragmaAlignPack() { + if (AlignPackStack.Stack.empty()) + return; + bool IsInnermost = true; + + // FIXME: AlignPackStack may contain both #pragma align and #pragma pack + // information, diagnostics below might not be accurate if we have mixed + // pragmas. + for (const auto &StackSlot : llvm::reverse(AlignPackStack.Stack)) { + Diag(StackSlot.PragmaPushLocation, diag::warn_pragma_pack_no_pop_eof); + // The user might have already reset the alignment, so suggest replacing + // the reset with a pop. + if (IsInnermost && + AlignPackStack.CurrentValue == AlignPackStack.DefaultValue) { + auto DB = Diag(AlignPackStack.CurrentPragmaLocation, + diag::note_pragma_pack_pop_instead_reset); + SourceLocation FixItLoc = + Lexer::findLocationAfterToken(AlignPackStack.CurrentPragmaLocation, + tok::l_paren, SourceMgr, LangOpts, + /*SkipTrailing=*/false); + if (FixItLoc.isValid()) + DB << FixItHint::CreateInsertion(FixItLoc, "pop"); + } + IsInnermost = false; + } + } + + void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) { + MSStructPragmaOn = (Kind == PMSST_ON); + } + + void Sema::ActOnPragmaMSComment(SourceLocation CommentLoc, + PragmaMSCommentKind Kind, StringRef Arg) { + auto *PCD = PragmaCommentDecl::Create( + Context, Context.getTranslationUnitDecl(), CommentLoc, Kind, Arg); + Context.getTranslationUnitDecl()->addDecl(PCD); + Consumer.HandleTopLevelDecl(DeclGroupRef(PCD)); + } + + void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value) { + auto *PDMD = PragmaDetectMismatchDecl::Create( + Context, Context.getTranslationUnitDecl(), Loc, Name, Value); + Context.getTranslationUnitDecl()->addDecl(PDMD); + Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD)); + } + + void Sema::ActOnPragmaFPEvalMethod(SourceLocation Loc, + LangOptions::FPEvalMethodKind Value) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + switch (Value) { + default: + llvm_unreachable("invalid pragma eval_method kind"); + case LangOptions::FEM_Source: + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Source); + break; + case LangOptions::FEM_Double: + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Double); + break; + case LangOptions::FEM_Extended: + NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended); + break; + } + if (getLangOpts().ApproxFunc) + Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) << 0 << 0; + if (getLangOpts().AllowFPReassoc) + Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) << 0 << 1; + if (getLangOpts().AllowRecip) + Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) << 0 << 2; + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + PP.setCurrentFPEvalMethod(Loc, Value); + } + + void Sema::ActOnPragmaFloatControl(SourceLocation Loc, + PragmaMsStackAction Action, + PragmaFloatControlKind Value) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) && + !CurContext->getRedeclContext()->isFileContext()) { + // Push and pop can only occur at file or namespace scope, or within a + // language linkage declaration. + Diag(Loc, diag::err_pragma_fc_pp_scope); + return; + } + switch (Value) { + default: + llvm_unreachable("invalid pragma float_control kind"); + case PFC_Precise: + NewFPFeatures.setFPPreciseEnabled(true); + FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); +- if (PP.getCurrentFPEvalMethod() == +- LangOptions::FPEvalMethodKind::FEM_Indeterminable && +- PP.getLastFPEvalPragmaLocation().isValid()) +- // A preceding `pragma float_control(precise,off)` has changed +- // the value of the evaluation method. +- // Set it back to its old value. +- PP.setCurrentFPEvalMethod(SourceLocation(), PP.getLastFPEvalMethod()); + break; + case PFC_NoPrecise: + if (CurFPFeatures.getExceptionMode() == LangOptions::FPE_Strict) + Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept); + else if (CurFPFeatures.getAllowFEnvAccess()) + Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv); + else + NewFPFeatures.setFPPreciseEnabled(false); + FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); +- PP.setLastFPEvalMethod(PP.getCurrentFPEvalMethod()); +- // `AllowFPReassoc` or `AllowReciprocal` option is enabled. +- PP.setCurrentFPEvalMethod( +- Loc, LangOptions::FPEvalMethodKind::FEM_Indeterminable); + break; + case PFC_Except: + if (!isPreciseFPEnabled()) + Diag(Loc, diag::err_pragma_fc_except_requires_precise); + else + NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Strict); + FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); + break; + case PFC_NoExcept: + NewFPFeatures.setSpecifiedExceptionModeOverride(LangOptions::FPE_Ignore); + FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); + break; + case PFC_Push: + FpPragmaStack.Act(Loc, Sema::PSK_Push_Set, StringRef(), NewFPFeatures); + break; + case PFC_Pop: + if (FpPragmaStack.Stack.empty()) { + Diag(Loc, diag::warn_pragma_pop_failed) << "float_control" + << "stack empty"; + return; + } + FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures); + NewFPFeatures = FpPragmaStack.CurrentValue; +- if (CurFPFeatures.getAllowFPReassociate() || +- CurFPFeatures.getAllowReciprocal()) +- // Since we are popping the pragma, we don't want to be passing +- // a location here. +- PP.setCurrentFPEvalMethod(SourceLocation(), +- CurFPFeatures.getFPEvalMethod()); + break; + } + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + } + + void Sema::ActOnPragmaMSPointersToMembers( + LangOptions::PragmaMSPointersToMembersKind RepresentationMethod, + SourceLocation PragmaLoc) { + MSPointerToMemberRepresentationMethod = RepresentationMethod; + ImplicitMSInheritanceAttrLoc = PragmaLoc; + } + + void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, + SourceLocation PragmaLoc, + MSVtorDispMode Mode) { + if (Action & PSK_Pop && VtorDispStack.Stack.empty()) + Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp" + << "stack empty"; + VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode); + } + + template <> + void Sema::PragmaStack::Act(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + AlignPackInfo Value) { + if (Action == PSK_Reset) { + CurrentValue = DefaultValue; + CurrentPragmaLocation = PragmaLocation; + return; + } + if (Action & PSK_Push) + Stack.emplace_back(Slot(StackSlotLabel, CurrentValue, CurrentPragmaLocation, + PragmaLocation)); + else if (Action & PSK_Pop) { + if (!StackSlotLabel.empty()) { + // If we've got a label, try to find it and jump there. + auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) { + return x.StackSlotLabel == StackSlotLabel; + }); + // We found the label, so pop from there. + if (I != Stack.rend()) { + CurrentValue = I->Value; + CurrentPragmaLocation = I->PragmaLocation; + Stack.erase(std::prev(I.base()), Stack.end()); + } + } else if (Value.IsXLStack() && Value.IsAlignAttr() && + CurrentValue.IsPackAttr()) { + // XL '#pragma align(reset)' would pop the stack until + // a current in effect pragma align is popped. + auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) { + return x.Value.IsAlignAttr(); + }); + // If we found pragma align so pop from there. + if (I != Stack.rend()) { + Stack.erase(std::prev(I.base()), Stack.end()); + if (Stack.empty()) { + CurrentValue = DefaultValue; + CurrentPragmaLocation = PragmaLocation; + } else { + CurrentValue = Stack.back().Value; + CurrentPragmaLocation = Stack.back().PragmaLocation; + Stack.pop_back(); + } + } + } else if (!Stack.empty()) { + // xl '#pragma align' sets the baseline, and `#pragma pack` cannot pop + // over the baseline. + if (Value.IsXLStack() && Value.IsPackAttr() && CurrentValue.IsAlignAttr()) + return; + + // We don't have a label, just pop the last entry. + CurrentValue = Stack.back().Value; + CurrentPragmaLocation = Stack.back().PragmaLocation; + Stack.pop_back(); + } + } + if (Action & PSK_Set) { + CurrentValue = Value; + CurrentPragmaLocation = PragmaLocation; + } + } + + bool Sema::UnifySection(StringRef SectionName, int SectionFlags, + NamedDecl *Decl) { + SourceLocation PragmaLocation; + if (auto A = Decl->getAttr()) + if (A->isImplicit()) + PragmaLocation = A->getLocation(); + auto SectionIt = Context.SectionInfos.find(SectionName); + if (SectionIt == Context.SectionInfos.end()) { + Context.SectionInfos[SectionName] = + ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags); + return false; + } + // A pre-declared section takes precedence w/o diagnostic. + const auto &Section = SectionIt->second; + if (Section.SectionFlags == SectionFlags || + ((SectionFlags & ASTContext::PSF_Implicit) && + !(Section.SectionFlags & ASTContext::PSF_Implicit))) + return false; + Diag(Decl->getLocation(), diag::err_section_conflict) << Decl << Section; + if (Section.Decl) + Diag(Section.Decl->getLocation(), diag::note_declared_at) + << Section.Decl->getName(); + if (PragmaLocation.isValid()) + Diag(PragmaLocation, diag::note_pragma_entered_here); + if (Section.PragmaSectionLocation.isValid()) + Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here); + return true; + } + + bool Sema::UnifySection(StringRef SectionName, + int SectionFlags, + SourceLocation PragmaSectionLocation) { + auto SectionIt = Context.SectionInfos.find(SectionName); + if (SectionIt != Context.SectionInfos.end()) { + const auto &Section = SectionIt->second; + if (Section.SectionFlags == SectionFlags) + return false; + if (!(Section.SectionFlags & ASTContext::PSF_Implicit)) { + Diag(PragmaSectionLocation, diag::err_section_conflict) + << "this" << Section; + if (Section.Decl) + Diag(Section.Decl->getLocation(), diag::note_declared_at) + << Section.Decl->getName(); + if (Section.PragmaSectionLocation.isValid()) + Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here); + return true; + } + } + Context.SectionInfos[SectionName] = + ASTContext::SectionInfo(nullptr, PragmaSectionLocation, SectionFlags); + return false; + } + + /// Called on well formed \#pragma bss_seg(). + void Sema::ActOnPragmaMSSeg(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + llvm::StringRef StackSlotLabel, + StringLiteral *SegmentName, + llvm::StringRef PragmaName) { + PragmaStack *Stack = + llvm::StringSwitch *>(PragmaName) + .Case("data_seg", &DataSegStack) + .Case("bss_seg", &BSSSegStack) + .Case("const_seg", &ConstSegStack) + .Case("code_seg", &CodeSegStack); + if (Action & PSK_Pop && Stack->Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << PragmaName + << "stack empty"; + if (SegmentName) { + if (!checkSectionName(SegmentName->getBeginLoc(), SegmentName->getString())) + return; + + if (SegmentName->getString() == ".drectve" && + Context.getTargetInfo().getCXXABI().isMicrosoft()) + Diag(PragmaLocation, diag::warn_attribute_section_drectve) << PragmaName; + } + + Stack->Act(PragmaLocation, Action, StackSlotLabel, SegmentName); + } + + /// Called on well formed \#pragma strict_gs_check(). + void Sema::ActOnPragmaMSStrictGuardStackCheck(SourceLocation PragmaLocation, + PragmaMsStackAction Action, + bool Value) { + if (Action & PSK_Pop && StrictGuardStackCheckStack.Stack.empty()) + Diag(PragmaLocation, diag::warn_pragma_pop_failed) << "strict_gs_check" + << "stack empty"; + + StrictGuardStackCheckStack.Act(PragmaLocation, Action, StringRef(), Value); + } + + /// Called on well formed \#pragma bss_seg(). + void Sema::ActOnPragmaMSSection(SourceLocation PragmaLocation, + int SectionFlags, StringLiteral *SegmentName) { + UnifySection(SegmentName->getString(), SectionFlags, PragmaLocation); + } + + void Sema::ActOnPragmaMSInitSeg(SourceLocation PragmaLocation, + StringLiteral *SegmentName) { + // There's no stack to maintain, so we just have a current section. When we + // see the default section, reset our current section back to null so we stop + // tacking on unnecessary attributes. + CurInitSeg = SegmentName->getString() == ".CRT$XCU" ? nullptr : SegmentName; + CurInitSegLoc = PragmaLocation; + } + + void Sema::ActOnPragmaMSAllocText( + SourceLocation PragmaLocation, StringRef Section, + const SmallVector> + &Functions) { + if (!CurContext->getRedeclContext()->isFileContext()) { + Diag(PragmaLocation, diag::err_pragma_expected_file_scope) << "alloc_text"; + return; + } + + for (auto &Function : Functions) { + IdentifierInfo *II; + SourceLocation Loc; + std::tie(II, Loc) = Function; + + DeclarationName DN(II); + NamedDecl *ND = LookupSingleName(TUScope, DN, Loc, LookupOrdinaryName); + if (!ND) { + Diag(Loc, diag::err_undeclared_use) << II->getName(); + return; + } + + auto *FD = dyn_cast(ND->getCanonicalDecl()); + if (!FD) { + Diag(Loc, diag::err_pragma_alloc_text_not_function); + return; + } + + if (getLangOpts().CPlusPlus && !FD->isInExternCContext()) { + Diag(Loc, diag::err_pragma_alloc_text_c_linkage); + return; + } + + FunctionToSectionMap[II->getName()] = std::make_tuple(Section, Loc); + } + } + + void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, + SourceLocation PragmaLoc) { + + IdentifierInfo *Name = IdTok.getIdentifierInfo(); + LookupResult Lookup(*this, Name, IdTok.getLocation(), LookupOrdinaryName); + LookupParsedName(Lookup, curScope, nullptr, true); + + if (Lookup.empty()) { + Diag(PragmaLoc, diag::warn_pragma_unused_undeclared_var) + << Name << SourceRange(IdTok.getLocation()); + return; + } + + VarDecl *VD = Lookup.getAsSingle(); + if (!VD) { + Diag(PragmaLoc, diag::warn_pragma_unused_expected_var_arg) + << Name << SourceRange(IdTok.getLocation()); + return; + } + + // Warn if this was used before being marked unused. + if (VD->isUsed()) + Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name; + + VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation(), + AttributeCommonInfo::AS_Pragma, + UnusedAttr::GNU_unused)); + } + + void Sema::AddCFAuditedAttribute(Decl *D) { + IdentifierInfo *Ident; + SourceLocation Loc; + std::tie(Ident, Loc) = PP.getPragmaARCCFCodeAuditedInfo(); + if (!Loc.isValid()) return; + + // Don't add a redundant or conflicting attribute. + if (D->hasAttr() || + D->hasAttr()) + return; + + AttributeCommonInfo Info(Ident, SourceRange(Loc), + AttributeCommonInfo::AS_Pragma); + D->addAttr(CFAuditedTransferAttr::CreateImplicit(Context, Info)); + } + + namespace { + + std::optional + getParentAttrMatcherRule(attr::SubjectMatchRule Rule) { + using namespace attr; + switch (Rule) { + default: + return std::nullopt; + #define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) + #define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \ + case Value: \ + return Parent; + #include "clang/Basic/AttrSubMatchRulesList.inc" + } + } + + bool isNegatedAttrMatcherSubRule(attr::SubjectMatchRule Rule) { + using namespace attr; + switch (Rule) { + default: + return false; + #define ATTR_MATCH_RULE(Value, Spelling, IsAbstract) + #define ATTR_MATCH_SUB_RULE(Value, Spelling, IsAbstract, Parent, IsNegated) \ + case Value: \ + return IsNegated; + #include "clang/Basic/AttrSubMatchRulesList.inc" + } + } + + CharSourceRange replacementRangeForListElement(const Sema &S, + SourceRange Range) { + // Make sure that the ',' is removed as well. + SourceLocation AfterCommaLoc = Lexer::findLocationAfterToken( + Range.getEnd(), tok::comma, S.getSourceManager(), S.getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/false); + if (AfterCommaLoc.isValid()) + return CharSourceRange::getCharRange(Range.getBegin(), AfterCommaLoc); + else + return CharSourceRange::getTokenRange(Range); + } + + std::string + attrMatcherRuleListToString(ArrayRef Rules) { + std::string Result; + llvm::raw_string_ostream OS(Result); + for (const auto &I : llvm::enumerate(Rules)) { + if (I.index()) + OS << (I.index() == Rules.size() - 1 ? ", and " : ", "); + OS << "'" << attr::getSubjectMatchRuleSpelling(I.value()) << "'"; + } + return Result; + } + + } // end anonymous namespace + + void Sema::ActOnPragmaAttributeAttribute( + ParsedAttr &Attribute, SourceLocation PragmaLoc, + attr::ParsedSubjectMatchRuleSet Rules) { + Attribute.setIsPragmaClangAttribute(); + SmallVector SubjectMatchRules; + // Gather the subject match rules that are supported by the attribute. + SmallVector, 4> + StrictSubjectMatchRuleSet; + Attribute.getMatchRules(LangOpts, StrictSubjectMatchRuleSet); + + // Figure out which subject matching rules are valid. + if (StrictSubjectMatchRuleSet.empty()) { + // Check for contradicting match rules. Contradicting match rules are + // either: + // - a top-level rule and one of its sub-rules. E.g. variable and + // variable(is_parameter). + // - a sub-rule and a sibling that's negated. E.g. + // variable(is_thread_local) and variable(unless(is_parameter)) + llvm::SmallDenseMap, 2> + RulesToFirstSpecifiedNegatedSubRule; + for (const auto &Rule : Rules) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + std::optional ParentRule = + getParentAttrMatcherRule(MatchRule); + if (!ParentRule) + continue; + auto It = Rules.find(*ParentRule); + if (It != Rules.end()) { + // A sub-rule contradicts a parent rule. + Diag(Rule.second.getBegin(), + diag::err_pragma_attribute_matcher_subrule_contradicts_rule) + << attr::getSubjectMatchRuleSpelling(MatchRule) + << attr::getSubjectMatchRuleSpelling(*ParentRule) << It->second + << FixItHint::CreateRemoval( + replacementRangeForListElement(*this, Rule.second)); + // Keep going without removing this rule as it won't change the set of + // declarations that receive the attribute. + continue; + } + if (isNegatedAttrMatcherSubRule(MatchRule)) + RulesToFirstSpecifiedNegatedSubRule.insert( + std::make_pair(*ParentRule, Rule)); + } + bool IgnoreNegatedSubRules = false; + for (const auto &Rule : Rules) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + std::optional ParentRule = + getParentAttrMatcherRule(MatchRule); + if (!ParentRule) + continue; + auto It = RulesToFirstSpecifiedNegatedSubRule.find(*ParentRule); + if (It != RulesToFirstSpecifiedNegatedSubRule.end() && + It->second != Rule) { + // Negated sub-rule contradicts another sub-rule. + Diag( + It->second.second.getBegin(), + diag:: + err_pragma_attribute_matcher_negated_subrule_contradicts_subrule) + << attr::getSubjectMatchRuleSpelling( + attr::SubjectMatchRule(It->second.first)) + << attr::getSubjectMatchRuleSpelling(MatchRule) << Rule.second + << FixItHint::CreateRemoval( + replacementRangeForListElement(*this, It->second.second)); + // Keep going but ignore all of the negated sub-rules. + IgnoreNegatedSubRules = true; + RulesToFirstSpecifiedNegatedSubRule.erase(It); + } + } + + if (!IgnoreNegatedSubRules) { + for (const auto &Rule : Rules) + SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first)); + } else { + for (const auto &Rule : Rules) { + if (!isNegatedAttrMatcherSubRule(attr::SubjectMatchRule(Rule.first))) + SubjectMatchRules.push_back(attr::SubjectMatchRule(Rule.first)); + } + } + Rules.clear(); + } else { + // Each rule in Rules must be a strict subset of the attribute's + // SubjectMatch rules. I.e. we're allowed to use + // `apply_to=variables(is_global)` on an attrubute with SubjectList<[Var]>, + // but should not allow `apply_to=variables` on an attribute which has + // `SubjectList<[GlobalVar]>`. + for (const auto &StrictRule : StrictSubjectMatchRuleSet) { + // First, check for exact match. + if (Rules.erase(StrictRule.first)) { + // Add the rule to the set of attribute receivers only if it's supported + // in the current language mode. + if (StrictRule.second) + SubjectMatchRules.push_back(StrictRule.first); + } + } + // Check remaining rules for subset matches. + auto RulesToCheck = Rules; + for (const auto &Rule : RulesToCheck) { + attr::SubjectMatchRule MatchRule = attr::SubjectMatchRule(Rule.first); + if (auto ParentRule = getParentAttrMatcherRule(MatchRule)) { + if (llvm::any_of(StrictSubjectMatchRuleSet, + [ParentRule](const auto &StrictRule) { + return StrictRule.first == *ParentRule && + StrictRule.second; // IsEnabled + })) { + SubjectMatchRules.push_back(MatchRule); + Rules.erase(MatchRule); + } + } + } + } + + if (!Rules.empty()) { + auto Diagnostic = + Diag(PragmaLoc, diag::err_pragma_attribute_invalid_matchers) + << Attribute; + SmallVector ExtraRules; + for (const auto &Rule : Rules) { + ExtraRules.push_back(attr::SubjectMatchRule(Rule.first)); + Diagnostic << FixItHint::CreateRemoval( + replacementRangeForListElement(*this, Rule.second)); + } + Diagnostic << attrMatcherRuleListToString(ExtraRules); + } + + if (PragmaAttributeStack.empty()) { + Diag(PragmaLoc, diag::err_pragma_attr_attr_no_push); + return; + } + + PragmaAttributeStack.back().Entries.push_back( + {PragmaLoc, &Attribute, std::move(SubjectMatchRules), /*IsUsed=*/false}); + } + + void Sema::ActOnPragmaAttributeEmptyPush(SourceLocation PragmaLoc, + const IdentifierInfo *Namespace) { + PragmaAttributeStack.emplace_back(); + PragmaAttributeStack.back().Loc = PragmaLoc; + PragmaAttributeStack.back().Namespace = Namespace; + } + + void Sema::ActOnPragmaAttributePop(SourceLocation PragmaLoc, + const IdentifierInfo *Namespace) { + if (PragmaAttributeStack.empty()) { + Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1; + return; + } + + // Dig back through the stack trying to find the most recently pushed group + // that in Namespace. Note that this works fine if no namespace is present, + // think of push/pops without namespaces as having an implicit "nullptr" + // namespace. + for (size_t Index = PragmaAttributeStack.size(); Index;) { + --Index; + if (PragmaAttributeStack[Index].Namespace == Namespace) { + for (const PragmaAttributeEntry &Entry : + PragmaAttributeStack[Index].Entries) { + if (!Entry.IsUsed) { + assert(Entry.Attribute && "Expected an attribute"); + Diag(Entry.Attribute->getLoc(), diag::warn_pragma_attribute_unused) + << *Entry.Attribute; + Diag(PragmaLoc, diag::note_pragma_attribute_region_ends_here); + } + } + PragmaAttributeStack.erase(PragmaAttributeStack.begin() + Index); + return; + } + } + + if (Namespace) + Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) + << 0 << Namespace->getName(); + else + Diag(PragmaLoc, diag::err_pragma_attribute_stack_mismatch) << 1; + } + + void Sema::AddPragmaAttributes(Scope *S, Decl *D) { + if (PragmaAttributeStack.empty()) + return; + for (auto &Group : PragmaAttributeStack) { + for (auto &Entry : Group.Entries) { + ParsedAttr *Attribute = Entry.Attribute; + assert(Attribute && "Expected an attribute"); + assert(Attribute->isPragmaClangAttribute() && + "expected #pragma clang attribute"); + + // Ensure that the attribute can be applied to the given declaration. + bool Applies = false; + for (const auto &Rule : Entry.MatchRules) { + if (Attribute->appliesToDecl(D, Rule)) { + Applies = true; + break; + } + } + if (!Applies) + continue; + Entry.IsUsed = true; + PragmaAttributeCurrentTargetDecl = D; + ParsedAttributesView Attrs; + Attrs.addAtEnd(Attribute); + ProcessDeclAttributeList(S, D, Attrs); + PragmaAttributeCurrentTargetDecl = nullptr; + } + } + } + + void Sema::PrintPragmaAttributeInstantiationPoint() { + assert(PragmaAttributeCurrentTargetDecl && "Expected an active declaration"); + Diags.Report(PragmaAttributeCurrentTargetDecl->getBeginLoc(), + diag::note_pragma_attribute_applied_decl_here); + } + + void Sema::DiagnoseUnterminatedPragmaAttribute() { + if (PragmaAttributeStack.empty()) + return; + Diag(PragmaAttributeStack.back().Loc, diag::err_pragma_attribute_no_pop_eof); + } + + void Sema::ActOnPragmaOptimize(bool On, SourceLocation PragmaLoc) { + if(On) + OptimizeOffPragmaLocation = SourceLocation(); + else + OptimizeOffPragmaLocation = PragmaLoc; + } + + void Sema::ActOnPragmaMSOptimize(SourceLocation Loc, bool IsOn) { + if (!CurContext->getRedeclContext()->isFileContext()) { + Diag(Loc, diag::err_pragma_expected_file_scope) << "optimize"; + return; + } + + MSPragmaOptimizeIsOn = IsOn; + } + + void Sema::ActOnPragmaMSFunction( + SourceLocation Loc, const llvm::SmallVectorImpl &NoBuiltins) { + if (!CurContext->getRedeclContext()->isFileContext()) { + Diag(Loc, diag::err_pragma_expected_file_scope) << "function"; + return; + } + + MSFunctionNoBuiltins.insert(NoBuiltins.begin(), NoBuiltins.end()); + } + + void Sema::AddRangeBasedOptnone(FunctionDecl *FD) { + // In the future, check other pragmas if they're implemented (e.g. pragma + // optimize 0 will probably map to this functionality too). + if(OptimizeOffPragmaLocation.isValid()) + AddOptnoneAttributeIfNoConflicts(FD, OptimizeOffPragmaLocation); + } + + void Sema::AddSectionMSAllocText(FunctionDecl *FD) { + if (!FD->getIdentifier()) + return; + + StringRef Name = FD->getName(); + auto It = FunctionToSectionMap.find(Name); + if (It != FunctionToSectionMap.end()) { + StringRef Section; + SourceLocation Loc; + std::tie(Section, Loc) = It->second; + + if (!FD->hasAttr()) + FD->addAttr(SectionAttr::CreateImplicit(Context, Section)); + } + } + + void Sema::ModifyFnAttributesMSPragmaOptimize(FunctionDecl *FD) { + // Don't modify the function attributes if it's "on". "on" resets the + // optimizations to the ones listed on the command line + if (!MSPragmaOptimizeIsOn) + AddOptnoneAttributeIfNoConflicts(FD, FD->getBeginLoc()); + } + + void Sema::AddOptnoneAttributeIfNoConflicts(FunctionDecl *FD, + SourceLocation Loc) { + // Don't add a conflicting attribute. No diagnostic is needed. + if (FD->hasAttr() || FD->hasAttr()) + return; + + // Add attributes only if required. Optnone requires noinline as well, but if + // either is already present then don't bother adding them. + if (!FD->hasAttr()) + FD->addAttr(OptimizeNoneAttr::CreateImplicit(Context, Loc)); + if (!FD->hasAttr()) + FD->addAttr(NoInlineAttr::CreateImplicit(Context, Loc)); + } + + void Sema::AddImplicitMSFunctionNoBuiltinAttr(FunctionDecl *FD) { + SmallVector V(MSFunctionNoBuiltins.begin(), + MSFunctionNoBuiltins.end()); + if (!MSFunctionNoBuiltins.empty()) + FD->addAttr(NoBuiltinAttr::CreateImplicit(Context, V.data(), V.size())); + } + + typedef std::vector > VisStack; + enum : unsigned { NoVisibility = ~0U }; + + void Sema::AddPushedVisibilityAttribute(Decl *D) { + if (!VisContext) + return; + + NamedDecl *ND = dyn_cast(D); + if (ND && ND->getExplicitVisibility(NamedDecl::VisibilityForValue)) + return; + + VisStack *Stack = static_cast(VisContext); + unsigned rawType = Stack->back().first; + if (rawType == NoVisibility) return; + + VisibilityAttr::VisibilityType type + = (VisibilityAttr::VisibilityType) rawType; + SourceLocation loc = Stack->back().second; + + D->addAttr(VisibilityAttr::CreateImplicit(Context, type, loc)); + } + + /// FreeVisContext - Deallocate and null out VisContext. + void Sema::FreeVisContext() { + delete static_cast(VisContext); + VisContext = nullptr; + } + + static void PushPragmaVisibility(Sema &S, unsigned type, SourceLocation loc) { + // Put visibility on stack. + if (!S.VisContext) + S.VisContext = new VisStack; + + VisStack *Stack = static_cast(S.VisContext); + Stack->push_back(std::make_pair(type, loc)); + } + + void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType, + SourceLocation PragmaLoc) { + if (VisType) { + // Compute visibility to use. + VisibilityAttr::VisibilityType T; + if (!VisibilityAttr::ConvertStrToVisibilityType(VisType->getName(), T)) { + Diag(PragmaLoc, diag::warn_attribute_unknown_visibility) << VisType; + return; + } + PushPragmaVisibility(*this, T, PragmaLoc); + } else { + PopPragmaVisibility(false, PragmaLoc); + } + } + + void Sema::ActOnPragmaFPContract(SourceLocation Loc, + LangOptions::FPModeKind FPC) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + switch (FPC) { + case LangOptions::FPM_On: + NewFPFeatures.setAllowFPContractWithinStatement(); + break; + case LangOptions::FPM_Fast: + NewFPFeatures.setAllowFPContractAcrossStatement(); + break; + case LangOptions::FPM_Off: + NewFPFeatures.setDisallowFPContract(); + break; + case LangOptions::FPM_FastHonorPragmas: + llvm_unreachable("Should not happen"); + } + FpPragmaStack.Act(Loc, Sema::PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + } + + void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) { + if (IsEnabled) { + // For value unsafe context, combining this pragma with eval method + // setting is not recommended. See comment in function FixupInvocation#506. + int Reason = -1; + if (getLangOpts().getFPEvalMethod() != LangOptions::FEM_UnsetOnCommandLine) + // Eval method set using the option 'ffp-eval-method'. + Reason = 1; + if (PP.getLastFPEvalPragmaLocation().isValid()) + // Eval method set using the '#pragma clang fp eval_method'. + // We could have both an option and a pragma used to the set the eval + // method. The pragma overrides the option in the command line. The Reason + // of the diagnostic is overriden too. + Reason = 0; + if (Reason != -1) + Diag(Loc, diag::err_setting_eval_method_used_in_unsafe_context) + << Reason << 4; + } + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + NewFPFeatures.setAllowFPReassociateOverride(IsEnabled); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + } + + void Sema::ActOnPragmaFEnvRound(SourceLocation Loc, llvm::RoundingMode FPR) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + NewFPFeatures.setConstRoundingModeOverride(FPR); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + } + + void Sema::setExceptionMode(SourceLocation Loc, + LangOptions::FPExceptionModeKind FPE) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + NewFPFeatures.setSpecifiedExceptionModeOverride(FPE); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + } + + void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { + FPOptionsOverride NewFPFeatures = CurFPFeatureOverrides(); + if (IsEnabled) { + // Verify Microsoft restriction: + // You can't enable fenv_access unless precise semantics are enabled. + // Precise semantics can be enabled either by the float_control + // pragma, or by using the /fp:precise or /fp:strict compiler options + if (!isPreciseFPEnabled()) + Diag(Loc, diag::err_pragma_fenv_requires_precise); + } + NewFPFeatures.setAllowFEnvAccessOverride(IsEnabled); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + } + + void Sema::ActOnPragmaFPExceptions(SourceLocation Loc, + LangOptions::FPExceptionModeKind FPE) { + setExceptionMode(Loc, FPE); + } + + void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, + SourceLocation Loc) { + // Visibility calculations will consider the namespace's visibility. + // Here we just want to note that we're in a visibility context + // which overrides any enclosing #pragma context, but doesn't itself + // contribute visibility. + PushPragmaVisibility(*this, NoVisibility, Loc); + } + + void Sema::PopPragmaVisibility(bool IsNamespaceEnd, SourceLocation EndLoc) { + if (!VisContext) { + Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch); + return; + } + + // Pop visibility from stack + VisStack *Stack = static_cast(VisContext); + + const std::pair *Back = &Stack->back(); + bool StartsWithPragma = Back->first != NoVisibility; + if (StartsWithPragma && IsNamespaceEnd) { + Diag(Back->second, diag::err_pragma_push_visibility_mismatch); + Diag(EndLoc, diag::note_surrounding_namespace_ends_here); + + // For better error recovery, eat all pushes inside the namespace. + do { + Stack->pop_back(); + Back = &Stack->back(); + StartsWithPragma = Back->first != NoVisibility; + } while (StartsWithPragma); + } else if (!StartsWithPragma && !IsNamespaceEnd) { + Diag(EndLoc, diag::err_pragma_pop_visibility_mismatch); + Diag(Back->second, diag::note_surrounding_namespace_starts_here); + return; + } + + Stack->pop_back(); + // To simplify the implementation, never keep around an empty stack. + if (Stack->empty()) + FreeVisContext(); + } + + template + static bool checkCommonAttributeFeatures(Sema &S, const Ty *Node, + const ParsedAttr &A, + bool SkipArgCountCheck) { + // Several attributes carry different semantics than the parsing requires, so + // those are opted out of the common argument checks. + // + // We also bail on unknown and ignored attributes because those are handled + // as part of the target-specific handling logic. + if (A.getKind() == ParsedAttr::UnknownAttribute) + return false; + // Check whether the attribute requires specific language extensions to be + // enabled. + if (!A.diagnoseLangOpts(S)) + return true; + // Check whether the attribute appertains to the given subject. + if (!A.diagnoseAppertainsTo(S, Node)) + return true; + // Check whether the attribute is mutually exclusive with other attributes + // that have already been applied to the declaration. + if (!A.diagnoseMutualExclusion(S, Node)) + return true; + // Check whether the attribute exists in the target architecture. + if (S.CheckAttrTarget(A)) + return true; + + if (A.hasCustomParsing()) + return false; + + if (!SkipArgCountCheck) { + if (A.getMinArgs() == A.getMaxArgs()) { + // If there are no optional arguments, then checking for the argument + // count is trivial. + if (!A.checkExactlyNumArgs(S, A.getMinArgs())) + return true; + } else { + // There are optional arguments, so checking is slightly more involved. + if (A.getMinArgs() && !A.checkAtLeastNumArgs(S, A.getMinArgs())) + return true; + else if (!A.hasVariadicArg() && A.getMaxArgs() && + !A.checkAtMostNumArgs(S, A.getMaxArgs())) + return true; + } + } + + return false; + } + + bool Sema::checkCommonAttributeFeatures(const Decl *D, const ParsedAttr &A, + bool SkipArgCountCheck) { + return ::checkCommonAttributeFeatures(*this, D, A, SkipArgCountCheck); + } + bool Sema::checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A, + bool SkipArgCountCheck) { + return ::checkCommonAttributeFeatures(*this, S, A, SkipArgCountCheck); + } +diff --git a/clang/test/CodeGen/X86/fexcess-precision.c b/clang/test/CodeGen/X86/fexcess-precision.c +index 325706830f89..68c2f7626091 100644 +--- a/clang/test/CodeGen/X86/fexcess-precision.c ++++ b/clang/test/CodeGen/X86/fexcess-precision.c +@@ -1,387 +1,387 @@ + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast -target-feature +avx512fp16 \ + // RUN: -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard -target-feature +avx512fp16 \ + // RUN: -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast \ + // RUN: -emit-llvm -ffp-eval-method=source -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=source -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard \ + // RUN: -emit-llvm -ffp-eval-method=source -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=source -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -emit-llvm -ffp-eval-method=source -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=source -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-NO-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast \ + // RUN: -emit-llvm -ffp-eval-method=double -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=double -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard \ + // RUN: -emit-llvm -ffp-eval-method=double -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=double -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -emit-llvm -ffp-eval-method=double -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=double -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast \ + // RUN: -emit-llvm -ffp-eval-method=extended -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-FP80 %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=fast -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=extended -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-FP80 %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard \ + // RUN: -emit-llvm -ffp-eval-method=extended -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-FP80 %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=standard -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=extended -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-FP80 %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -emit-llvm -ffp-eval-method=extended -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-FP80 %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -emit-llvm -ffp-eval-method=extended -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-EXT-FP80 %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -ffp-contract=on -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -ffp-contract=on -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -fmath-errno -ffp-contract=on -fno-rounding-math \ + // RUN: -ffp-eval-method=source -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -fmath-errno -ffp-contract=on -fno-rounding-math \ + // RUN: -ffp-eval-method=source -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -fmath-errno -ffp-contract=on -fno-rounding-math \ + // RUN: -ffp-eval-method=double -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -fmath-errno -ffp-contract=on -fno-rounding-math \ + // RUN: -ffp-eval-method=double -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT-DBL %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -fmath-errno -ffp-contract=on -fno-rounding-math \ + // RUN: -ffp-eval-method=extended -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -fmath-errno -ffp-contract=on -fno-rounding-math \ + // RUN: -ffp-eval-method=extended -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-CONTRACT-EXT %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none \ + // RUN: -fapprox-func -fmath-errno -fno-signed-zeros -mreassociate \ + // RUN: -freciprocal-math -ffp-contract=on -fno-rounding-math \ + // RUN: -funsafe-math-optimizations -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-UNSAFE %s + + // RUN: %clang_cc1 -triple x86_64-unknown-unknown \ + // RUN: -ffloat16-excess-precision=none -target-feature +avx512fp16 \ + // RUN: -fapprox-func -fmath-errno -fno-signed-zeros -mreassociate \ + // RUN: -freciprocal-math -ffp-contract=on -fno-rounding-math \ + // RUN: -funsafe-math-optimizations -emit-llvm -o - %s \ + // RUN: | FileCheck -check-prefixes=CHECK-UNSAFE %s + + // CHECK-EXT-LABEL: @f( + // CHECK-EXT-NEXT: entry: + // CHECK-EXT-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-EXT-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-EXT-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-EXT-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-EXT-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-EXT-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-EXT-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-EXT-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-EXT-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-EXT-NEXT: [[EXT:%.*]] = fpext half [[TMP0]] to float + // CHECK-EXT-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-EXT-NEXT: [[EXT1:%.*]] = fpext half [[TMP1]] to float + // CHECK-EXT-NEXT: [[MUL:%.*]] = fmul float [[EXT]], [[EXT1]] + // CHECK-EXT-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-EXT-NEXT: [[EXT2:%.*]] = fpext half [[TMP2]] to float + // CHECK-EXT-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-EXT-NEXT: [[EXT3:%.*]] = fpext half [[TMP3]] to float + // CHECK-EXT-NEXT: [[MUL4:%.*]] = fmul float [[EXT2]], [[EXT3]] + // CHECK-EXT-NEXT: [[ADD:%.*]] = fadd float [[MUL]], [[MUL4]] + // CHECK-EXT-NEXT: [[UNPROMOTION:%.*]] = fptrunc float [[ADD]] to half + // CHECK-EXT-NEXT: ret half [[UNPROMOTION]] + // + // CHECK-NO-EXT-LABEL: @f( + // CHECK-NO-EXT-NEXT: entry: + // CHECK-NO-EXT-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-NO-EXT-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-NO-EXT-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-NO-EXT-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-NO-EXT-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-NO-EXT-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-NO-EXT-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-NO-EXT-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-NO-EXT-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-NO-EXT-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-NO-EXT-NEXT: [[MUL:%.*]] = fmul half [[TMP0]], [[TMP1]] + // CHECK-NO-EXT-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-NO-EXT-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-NO-EXT-NEXT: [[MUL1:%.*]] = fmul half [[TMP2]], [[TMP3]] + // CHECK-NO-EXT-NEXT: [[ADD:%.*]] = fadd half [[MUL]], [[MUL1]] + // CHECK-NO-EXT-NEXT: ret half [[ADD]] + // + // CHECK-EXT-DBL-LABEL: @f( + // CHECK-EXT-DBL-NEXT: entry: + // CHECK-EXT-DBL-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-EXT-DBL-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-EXT-DBL-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-EXT-DBL-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-EXT-DBL-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-EXT-DBL-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-EXT-DBL-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-EXT-DBL-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-EXT-DBL-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-EXT-DBL-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to double + // CHECK-EXT-DBL-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-EXT-DBL-NEXT: [[CONV1:%.*]] = fpext half [[TMP1]] to double + // CHECK-EXT-DBL-NEXT: [[MUL:%.*]] = fmul double [[CONV]], [[CONV1]] + // CHECK-EXT-DBL-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-EXT-DBL-NEXT: [[CONV2:%.*]] = fpext half [[TMP2]] to double + // CHECK-EXT-DBL-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-EXT-DBL-NEXT: [[CONV3:%.*]] = fpext half [[TMP3]] to double + // CHECK-EXT-DBL-NEXT: [[MUL4:%.*]] = fmul double [[CONV2]], [[CONV3]] + // CHECK-EXT-DBL-NEXT: [[ADD:%.*]] = fadd double [[MUL]], [[MUL4]] + // CHECK-EXT-DBL-NEXT: [[CONV5:%.*]] = fptrunc double [[ADD]] to half + // CHECK-EXT-DBL-NEXT: ret half [[CONV5]] + // + // CHECK-EXT-FP80-LABEL: @f( + // CHECK-EXT-FP80-NEXT: entry: + // CHECK-EXT-FP80-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-EXT-FP80-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-EXT-FP80-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-EXT-FP80-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-EXT-FP80-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-EXT-FP80-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-EXT-FP80-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-EXT-FP80-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-EXT-FP80-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-EXT-FP80-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to x86_fp80 + // CHECK-EXT-FP80-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-EXT-FP80-NEXT: [[CONV1:%.*]] = fpext half [[TMP1]] to x86_fp80 + // CHECK-EXT-FP80-NEXT: [[MUL:%.*]] = fmul x86_fp80 [[CONV]], [[CONV1]] + // CHECK-EXT-FP80-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-EXT-FP80-NEXT: [[CONV2:%.*]] = fpext half [[TMP2]] to x86_fp80 + // CHECK-EXT-FP80-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-EXT-FP80-NEXT: [[CONV3:%.*]] = fpext half [[TMP3]] to x86_fp80 + // CHECK-EXT-FP80-NEXT: [[MUL4:%.*]] = fmul x86_fp80 [[CONV2]], [[CONV3]] + // CHECK-EXT-FP80-NEXT: [[ADD:%.*]] = fadd x86_fp80 [[MUL]], [[MUL4]] + // CHECK-EXT-FP80-NEXT: [[CONV5:%.*]] = fptrunc x86_fp80 [[ADD]] to half + // CHECK-EXT-FP80-NEXT: ret half [[CONV5]] + // + // CHECK-CONTRACT-LABEL: @f( + // CHECK-CONTRACT-NEXT: entry: + // CHECK-CONTRACT-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-CONTRACT-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-CONTRACT-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-CONTRACT-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-CONTRACT-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-CONTRACT-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-CONTRACT-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-CONTRACT-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-CONTRACT-NEXT: [[MUL1:%.*]] = fmul half [[TMP2]], [[TMP3]] + // CHECK-CONTRACT-NEXT: [[TMP4:%.*]] = call half @llvm.fmuladd.f16(half [[TMP0]], half [[TMP1]], half [[MUL1]]) + // CHECK-CONTRACT-NEXT: ret half [[TMP4]] + // + // CHECK-CONTRACT-DBL-LABEL: @f( + // CHECK-CONTRACT-DBL-NEXT: entry: + // CHECK-CONTRACT-DBL-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-DBL-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-DBL-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-DBL-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-DBL-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to double + // CHECK-CONTRACT-DBL-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: [[CONV1:%.*]] = fpext half [[TMP1]] to double + // CHECK-CONTRACT-DBL-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: [[CONV2:%.*]] = fpext half [[TMP2]] to double + // CHECK-CONTRACT-DBL-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-CONTRACT-DBL-NEXT: [[CONV3:%.*]] = fpext half [[TMP3]] to double + // CHECK-CONTRACT-DBL-NEXT: [[MUL4:%.*]] = fmul double [[CONV2]], [[CONV3]] + // CHECK-CONTRACT-DBL-NEXT: [[TMP4:%.*]] = call double @llvm.fmuladd.f64(double [[CONV]], double [[CONV1]], double [[MUL4]]) + // CHECK-CONTRACT-DBL-NEXT: [[CONV5:%.*]] = fptrunc double [[TMP4]] to half + // CHECK-CONTRACT-DBL-NEXT: ret half [[CONV5]] + // + // CHECK-CONTRACT-EXT-LABEL: @f( + // CHECK-CONTRACT-EXT-NEXT: entry: + // CHECK-CONTRACT-EXT-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-EXT-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-EXT-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-EXT-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-CONTRACT-EXT-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: [[CONV:%.*]] = fpext half [[TMP0]] to x86_fp80 + // CHECK-CONTRACT-EXT-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: [[CONV1:%.*]] = fpext half [[TMP1]] to x86_fp80 + // CHECK-CONTRACT-EXT-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: [[CONV2:%.*]] = fpext half [[TMP2]] to x86_fp80 + // CHECK-CONTRACT-EXT-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-CONTRACT-EXT-NEXT: [[CONV3:%.*]] = fpext half [[TMP3]] to x86_fp80 + // CHECK-CONTRACT-EXT-NEXT: [[MUL4:%.*]] = fmul x86_fp80 [[CONV2]], [[CONV3]] + // CHECK-CONTRACT-EXT-NEXT: [[TMP4:%.*]] = call x86_fp80 @llvm.fmuladd.f80(x86_fp80 [[CONV]], x86_fp80 [[CONV1]], x86_fp80 [[MUL4]]) + // CHECK-CONTRACT-EXT-NEXT: [[CONV5:%.*]] = fptrunc x86_fp80 [[TMP4]] to half + // CHECK-CONTRACT-EXT-NEXT: ret half [[CONV5]] + // + // CHECK-UNSAFE-LABEL: @f( + // CHECK-UNSAFE-NEXT: entry: + // CHECK-UNSAFE-NEXT: [[A_ADDR:%.*]] = alloca half + // CHECK-UNSAFE-NEXT: [[B_ADDR:%.*]] = alloca half + // CHECK-UNSAFE-NEXT: [[C_ADDR:%.*]] = alloca half + // CHECK-UNSAFE-NEXT: [[D_ADDR:%.*]] = alloca half + // CHECK-UNSAFE-NEXT: store half [[A:%.*]], ptr [[A_ADDR]] + // CHECK-UNSAFE-NEXT: store half [[B:%.*]], ptr [[B_ADDR]] + // CHECK-UNSAFE-NEXT: store half [[C:%.*]], ptr [[C_ADDR]] + // CHECK-UNSAFE-NEXT: store half [[D:%.*]], ptr [[D_ADDR]] + // CHECK-UNSAFE-NEXT: [[TMP0:%.*]] = load half, ptr [[A_ADDR]] + // CHECK-UNSAFE-NEXT: [[TMP1:%.*]] = load half, ptr [[B_ADDR]] + // CHECK-UNSAFE-NEXT: [[TMP2:%.*]] = load half, ptr [[C_ADDR]] + // CHECK-UNSAFE-NEXT: [[TMP3:%.*]] = load half, ptr [[D_ADDR]] + // CHECK-UNSAFE-NEXT: [[MUL1:%.*]] = fmul reassoc nsz arcp afn half [[TMP2]], [[TMP3]] + // CHECK-UNSAFE-NEXT: [[TMP4:%.*]] = call reassoc nsz arcp afn half @llvm.fmuladd.f16(half [[TMP0]], half [[TMP1]], half [[MUL1]]) + // CHECK-UNSAFE-NEXT: ret half [[TMP4]] + // + _Float16 f(_Float16 a, _Float16 b, _Float16 c, _Float16 d) { + return a * b + c * d; + } + + // CHECK-EXT-LABEL: @getFEM( + // CHECK-EXT-NEXT: entry: + // CHECK-EXT-NEXT: ret i32 0 + // + // CHECK-NO-EXT-LABEL: @getFEM( + // CHECK-NO-EXT-NEXT: entry: + // CHECK-NO-EXT-NEXT: ret i32 0 + // + // CHECK-EXT-DBL-LABEL: @getFEM( + // CHECK-EXT-DBL-NEXT: entry: + // CHECK-EXT-DBL-NEXT: ret i32 1 + // + // CHECK-EXT-FP80-LABEL: @getFEM( + // CHECK-EXT-FP80-NEXT: entry: + // CHECK-EXT-FP80-NEXT: ret i32 2 + // + // CHECK-CONTRACT-LABEL: @getFEM( + // CHECK-CONTRACT-NEXT: entry: + // CHECK-CONTRACT-NEXT: ret i32 0 + // + // CHECK-CONTRACT-DBL-LABEL: @getFEM( + // CHECK-CONTRACT-DBL-NEXT: entry: + // CHECK-CONTRACT-DBL-NEXT: ret i32 1 + // + // CHECK-CONTRACT-EXT-LABEL: @getFEM( + // CHECK-CONTRACT-EXT-NEXT: entry: + // CHECK-CONTRACT-EXT-NEXT: ret i32 2 + // + // CHECK-UNSAFE-LABEL: @getFEM( + // CHECK-UNSAFE-NEXT: entry: +-// CHECK-UNSAFE-NEXT: ret i32 -1 ++// CHECK-UNSAFE-NEXT: ret i32 0 + // + int getFEM() { + return __FLT_EVAL_METHOD__; + } +diff --git a/clang/test/CodeGen/eval-method-fast-math.cpp b/clang/test/CodeGen/eval-method-fast-math.cpp +deleted file mode 100644 +index 0b5b3780efa3..000000000000 +--- a/clang/test/CodeGen/eval-method-fast-math.cpp ++++ /dev/null +@@ -1,117 +0,0 @@ +-// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +-// RUN: -triple x86_64-linux-gnu -emit-llvm -o - %s \ +-// RUN: | FileCheck %s -check-prefixes=CHECK +- +-// RUN: %clang_cc1 -triple i386--linux -emit-llvm -o - %s \ +-// RUN: | FileCheck %s -check-prefixes=CHECK-EXT +- +-// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +-// RUN: -mreassociate -freciprocal-math -ffp-contract=fast \ +-// RUN: -ffast-math -triple x86_64-linux-gnu \ +-// RUN: -emit-llvm -o - %s \ +-// RUN: | FileCheck %s -check-prefixes=CHECK-FAST +- +-// RUN: %clang_cc1 -triple i386--linux -mreassociate -freciprocal-math \ +-// RUN: -ffp-contract=fast -ffast-math -emit-llvm -o - %s \ +-// RUN: | FileCheck %s -check-prefixes=CHECK-FAST +- +-float a = 1.0f, b = 2.0f, c = 3.0f; +-#pragma float_control(precise, off) +-float res2 = a + b + c; +-int val3 = __FLT_EVAL_METHOD__; +-#pragma float_control(precise, on) +-float res3 = a + b + c; +-int val4 = __FLT_EVAL_METHOD__; +- +-// CHECK: @val3 = global i32 -1 +-// CHECK: @val4 = global i32 0 +- +-// CHECK-EXT: @val3 = global i32 -1 +-// CHECK-EXT: @val4 = global i32 2 +- +-// CHECK-FAST: @val3 = global i32 -1 +-// CHECK-FAST: @val4 = global i32 -1 +- +-float res; +-int add(float a, float b, float c) { +- // CHECK: fadd float +- // CHECK: load float, ptr +- // CHECK: fadd float +- // CHECK: store float +- // CHECK: ret i32 0 +- res = a + b + c; +- return __FLT_EVAL_METHOD__; +-} +- +-int add_precise(float a, float b, float c) { +-#pragma float_control(precise, on) +- // CHECK: fadd float +- // CHECK: load float, ptr +- // CHECK: fadd float +- // CHECK: store float +- // CHECK: ret i32 0 +- res = a + b + c; +- return __FLT_EVAL_METHOD__; +-} +- +-#pragma float_control(push) +-#pragma float_control(precise, on) +-int add_precise_1(float a, float b, float c) { +- // CHECK: fadd float +- // CHECK: load float, ptr +- // CHECK: fadd float +- // CHECK: store float +- // CHECK: ret i32 0 +- res = a + b + c; +- return __FLT_EVAL_METHOD__; +-} +-#pragma float_control(pop) +- +-int add_not_precise(float a, float b, float c) { +- // Fast-math is enabled with this pragma. +-#pragma float_control(precise, off) +- // CHECK: fadd fast float +- // CHECK: load float, ptr +- // CHECK: fadd fast float +- // CHECK: float {{.*}}, ptr +- // CHECK: ret i32 -1 +- res = a + b + c; +- return __FLT_EVAL_METHOD__; +-} +- +-#pragma float_control(push) +-// Fast-math is enabled with this pragma. +-#pragma float_control(precise, off) +-int add_not_precise_1(float a, float b, float c) { +- // CHECK: fadd fast float +- // CHECK: load float, ptr +- // CHECK: fadd fast float +- // CHECK: float {{.*}}, ptr +- // CHECK: ret i32 -1 +- res = a + b + c; +- return __FLT_EVAL_METHOD__; +-} +-#pragma float_control(pop) +- +-int getFPEvalMethod() { +- // CHECK: ret i32 0 +- return __FLT_EVAL_METHOD__; +-} +- +-float res1; +-int whatever(float a, float b, float c) { +-#pragma float_control(precise, off) +- // CHECK: load float, ptr +- // CHECK: fadd fast float +- // CHECK: store float {{.*}}, ptr +- // CHECK: store i32 -1 +- // CHECK: store i32 0 +- // CHECK: ret i32 -1 +- res1 = a + b + c; +- int val1 = __FLT_EVAL_METHOD__; +- { +-#pragma float_control(precise, on) +- int val2 = __FLT_EVAL_METHOD__; +- } +- return __FLT_EVAL_METHOD__; +-} +diff --git a/clang/test/Preprocessor/flt_eval_macro.cpp b/clang/test/Preprocessor/flt_eval_macro.cpp +index 37c28f21333f..5832458725a7 100644 +--- a/clang/test/Preprocessor/flt_eval_macro.cpp ++++ b/clang/test/Preprocessor/flt_eval_macro.cpp +@@ -1,88 +1,88 @@ + // RUN: %clang_cc1 -E -dM -triple=x86_64-none-none %s -o - \ + // RUN: | FileCheck %s -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple=x86_64-none-none -target-feature -sse \ + // RUN: %s -o - | FileCheck %s -check-prefix=EXT -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple=arm64e-apple-ios -target-feature -sse \ + // RUN: %s -o - | FileCheck %s -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple=arm64e-apple-ios -target-feature +sse \ + // RUN: %s -o - | FileCheck %s -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple=arm64_32-apple-ios %s -o - \ + // RUN: | FileCheck %s -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple=arm64_32-apple-ios -target-feature -sse \ + // RUN: %s -o - | FileCheck %s -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple=x86_64-apple-macos13.0 -ffast-math \ +-// RUN: %s -o - | FileCheck %s -check-prefix=CHECK-MINUS-ONE -strict-whitespace ++// RUN: %s -o - | FileCheck %s -check-prefix=CHECK -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple i386-pc-windows -target-cpu pentium4 %s -o - \ + // RUN: | FileCheck %s -strict-whitespace + + // RUN: %clang_cc1 -E -dM -triple i386-pc-windows -target-cpu pentium4 \ + // RUN: -target-feature -sse %s -o - | FileCheck -check-prefix=EXT %s \ + // RUN: -strict-whitespace + + #ifdef __FLT_EVAL_METHOD__ + #if __FLT_EVAL_METHOD__ == 3 + #define __GLIBC_FLT_EVAL_METHOD 2 + #else + #define __GLIBC_FLT_EVAL_METHOD __FLT_EVAL_METHOD__ + #endif + #elif defined __x86_64__ + #define __GLIBC_FLT_EVAL_METHOD 0 + #else + #define __GLIBC_FLT_EVAL_METHOD 2 + #endif + + #if __GLIBC_FLT_EVAL_METHOD == -1 + #define Name "MinusOne" + #elif __GLIBC_FLT_EVAL_METHOD == 0 || __GLIBC_FLT_EVAL_METHOD == 16 + #define Name "One" + #elif __GLIBC_FLT_EVAL_METHOD == 1 + #define Name "Two" + #elif __GLIBC_FLT_EVAL_METHOD == 2 + #define Name "Three" + #elif __GLIBC_FLT_EVAL_METHOD == 32 + #define Name "Four" + #elif __GLIBC_FLT_EVAL_METHOD == 33 + #define Name "Five" + #elif __GLIBC_FLT_EVAL_METHOD == 64 + #define Name "Six" + #elif __GLIBC_FLT_EVAL_METHOD == 65 + #define Name "Seven" + #elif __GLIBC_FLT_EVAL_METHOD == 128 + #define Name "Eight" + #elif __GLIBC_FLT_EVAL_METHOD == 129 + #define Name "Nine" + #else + #error "Unknown __GLIBC_FLT_EVAL_METHOD" + #endif + + int foo() { + // CHECK: #define Name "One" + // CHECK-MINUS-ONE: #define Name "MinusOne" + // EXT: #define Name "Three" + return Name; + } + + #pragma fp eval_method(double) + + #if __FLT_EVAL_METHOD__ == 3 + #define Val "Unset" + #elif __FLT_EVAL_METHOD__ == 0 + #define Val "val0" + #elif __FLT_EVAL_METHOD__ == 1 + #define Val "val1" + #elif __FLT_EVAL_METHOD__ == 2 + #define Val "val2" + #endif + + int goo() { + // CHECK: #define Val "val0" + // EXT: #define Val "val2" + return Val; + }