|  | //===--- ParsePragma.cpp - Language specific pragma parsing ---------------===// | 
|  | // | 
|  | // 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 language specific #pragma handlers. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/Basic/PragmaKinds.h" | 
|  | #include "clang/Basic/TargetInfo.h" | 
|  | #include "clang/Lex/Preprocessor.h" | 
|  | #include "clang/Parse/LoopHint.h" | 
|  | #include "clang/Parse/ParseDiagnostic.h" | 
|  | #include "clang/Parse/Parser.h" | 
|  | #include "clang/Parse/RAIIObjectsForParser.h" | 
|  | #include "clang/Sema/Scope.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | using namespace clang; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct PragmaAlignHandler : public PragmaHandler { | 
|  | explicit PragmaAlignHandler() : PragmaHandler("align") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaGCCVisibilityHandler : public PragmaHandler { | 
|  | explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaOptionsHandler : public PragmaHandler { | 
|  | explicit PragmaOptionsHandler() : PragmaHandler("options") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaPackHandler : public PragmaHandler { | 
|  | explicit PragmaPackHandler() : PragmaHandler("pack") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaClangSectionHandler : public PragmaHandler { | 
|  | explicit PragmaClangSectionHandler(Sema &S) | 
|  | : PragmaHandler("section"), Actions(S) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  |  | 
|  | private: | 
|  | Sema &Actions; | 
|  | }; | 
|  |  | 
|  | struct PragmaMSStructHandler : public PragmaHandler { | 
|  | explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaUnusedHandler : public PragmaHandler { | 
|  | PragmaUnusedHandler() : PragmaHandler("unused") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaWeakHandler : public PragmaHandler { | 
|  | explicit PragmaWeakHandler() : PragmaHandler("weak") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaRedefineExtnameHandler : public PragmaHandler { | 
|  | explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaOpenCLExtensionHandler : public PragmaHandler { | 
|  | PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  |  | 
|  | struct PragmaFPContractHandler : public PragmaHandler { | 
|  | PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | // Pragma STDC implementations. | 
|  |  | 
|  | /// PragmaSTDC_FENV_ACCESSHandler - "\#pragma STDC FENV_ACCESS ...". | 
|  | struct PragmaSTDC_FENV_ACCESSHandler : public PragmaHandler { | 
|  | PragmaSTDC_FENV_ACCESSHandler() : PragmaHandler("FENV_ACCESS") {} | 
|  |  | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &Tok) override { | 
|  | tok::OnOffSwitch OOS; | 
|  | if (PP.LexOnOffSwitch(OOS)) | 
|  | return; | 
|  | if (OOS == tok::OOS_ON) { | 
|  | PP.Diag(Tok, diag::warn_stdc_fenv_access_not_supported); | 
|  | return; | 
|  | } | 
|  |  | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | 
|  | 1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_fenv_access); | 
|  | Toks[0].setLocation(Tok.getLocation()); | 
|  | Toks[0].setAnnotationEndLoc(Tok.getLocation()); | 
|  | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | 
|  | static_cast<uintptr_t>(OOS))); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// PragmaSTDC_CX_LIMITED_RANGEHandler - "\#pragma STDC CX_LIMITED_RANGE ...". | 
|  | struct PragmaSTDC_CX_LIMITED_RANGEHandler : public PragmaHandler { | 
|  | PragmaSTDC_CX_LIMITED_RANGEHandler() : PragmaHandler("CX_LIMITED_RANGE") {} | 
|  |  | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &Tok) override { | 
|  | tok::OnOffSwitch OOS; | 
|  | PP.LexOnOffSwitch(OOS); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// PragmaSTDC_UnknownHandler - "\#pragma STDC ...". | 
|  | struct PragmaSTDC_UnknownHandler : public PragmaHandler { | 
|  | PragmaSTDC_UnknownHandler() = default; | 
|  |  | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &UnknownTok) override { | 
|  | // C99 6.10.6p2, unknown forms are not allowed. | 
|  | PP.Diag(UnknownTok, diag::ext_stdc_pragma_ignored); | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct PragmaFPHandler : public PragmaHandler { | 
|  | PragmaFPHandler() : PragmaHandler("fp") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaNoOpenMPHandler : public PragmaHandler { | 
|  | PragmaNoOpenMPHandler() : PragmaHandler("omp") { } | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaOpenMPHandler : public PragmaHandler { | 
|  | PragmaOpenMPHandler() : PragmaHandler("omp") { } | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | /// PragmaCommentHandler - "\#pragma comment ...". | 
|  | struct PragmaCommentHandler : public PragmaHandler { | 
|  | PragmaCommentHandler(Sema &Actions) | 
|  | : PragmaHandler("comment"), Actions(Actions) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  |  | 
|  | private: | 
|  | Sema &Actions; | 
|  | }; | 
|  |  | 
|  | struct PragmaDetectMismatchHandler : public PragmaHandler { | 
|  | PragmaDetectMismatchHandler(Sema &Actions) | 
|  | : PragmaHandler("detect_mismatch"), Actions(Actions) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  |  | 
|  | private: | 
|  | Sema &Actions; | 
|  | }; | 
|  |  | 
|  | struct PragmaFloatControlHandler : public PragmaHandler { | 
|  | PragmaFloatControlHandler(Sema &Actions) | 
|  | : PragmaHandler("float_control") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaMSPointersToMembers : public PragmaHandler { | 
|  | explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaMSVtorDisp : public PragmaHandler { | 
|  | explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaMSPragma : public PragmaHandler { | 
|  | explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | /// PragmaOptimizeHandler - "\#pragma clang optimize on/off". | 
|  | struct PragmaOptimizeHandler : public PragmaHandler { | 
|  | PragmaOptimizeHandler(Sema &S) | 
|  | : PragmaHandler("optimize"), Actions(S) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  |  | 
|  | private: | 
|  | Sema &Actions; | 
|  | }; | 
|  |  | 
|  | struct PragmaLoopHintHandler : public PragmaHandler { | 
|  | PragmaLoopHintHandler() : PragmaHandler("loop") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaUnrollHintHandler : public PragmaHandler { | 
|  | PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler { | 
|  | PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {} | 
|  | }; | 
|  |  | 
|  | struct PragmaMSIntrinsicHandler : public PragmaHandler { | 
|  | PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaMSOptimizeHandler : public PragmaHandler { | 
|  | PragmaMSOptimizeHandler() : PragmaHandler("optimize") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaForceCUDAHostDeviceHandler : public PragmaHandler { | 
|  | PragmaForceCUDAHostDeviceHandler(Sema &Actions) | 
|  | : PragmaHandler("force_cuda_host_device"), Actions(Actions) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  |  | 
|  | private: | 
|  | Sema &Actions; | 
|  | }; | 
|  |  | 
|  | /// PragmaAttributeHandler - "\#pragma clang attribute ...". | 
|  | struct PragmaAttributeHandler : public PragmaHandler { | 
|  | PragmaAttributeHandler(AttributeFactory &AttrFactory) | 
|  | : PragmaHandler("attribute"), AttributesForPragmaAttribute(AttrFactory) {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  |  | 
|  | /// A pool of attributes that were parsed in \#pragma clang attribute. | 
|  | ParsedAttributes AttributesForPragmaAttribute; | 
|  | }; | 
|  |  | 
|  | struct PragmaMaxTokensHereHandler : public PragmaHandler { | 
|  | PragmaMaxTokensHereHandler() : PragmaHandler("max_tokens_here") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | struct PragmaMaxTokensTotalHandler : public PragmaHandler { | 
|  | PragmaMaxTokensTotalHandler() : PragmaHandler("max_tokens_total") {} | 
|  | void HandlePragma(Preprocessor &PP, PragmaIntroducer Introducer, | 
|  | Token &FirstToken) override; | 
|  | }; | 
|  |  | 
|  | }  // end namespace | 
|  |  | 
|  | void Parser::initializePragmaHandlers() { | 
|  | AlignHandler = std::make_unique<PragmaAlignHandler>(); | 
|  | PP.AddPragmaHandler(AlignHandler.get()); | 
|  |  | 
|  | GCCVisibilityHandler = std::make_unique<PragmaGCCVisibilityHandler>(); | 
|  | PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get()); | 
|  |  | 
|  | OptionsHandler = std::make_unique<PragmaOptionsHandler>(); | 
|  | PP.AddPragmaHandler(OptionsHandler.get()); | 
|  |  | 
|  | PackHandler = std::make_unique<PragmaPackHandler>(); | 
|  | PP.AddPragmaHandler(PackHandler.get()); | 
|  |  | 
|  | MSStructHandler = std::make_unique<PragmaMSStructHandler>(); | 
|  | PP.AddPragmaHandler(MSStructHandler.get()); | 
|  |  | 
|  | UnusedHandler = std::make_unique<PragmaUnusedHandler>(); | 
|  | PP.AddPragmaHandler(UnusedHandler.get()); | 
|  |  | 
|  | WeakHandler = std::make_unique<PragmaWeakHandler>(); | 
|  | PP.AddPragmaHandler(WeakHandler.get()); | 
|  |  | 
|  | RedefineExtnameHandler = std::make_unique<PragmaRedefineExtnameHandler>(); | 
|  | PP.AddPragmaHandler(RedefineExtnameHandler.get()); | 
|  |  | 
|  | FPContractHandler = std::make_unique<PragmaFPContractHandler>(); | 
|  | PP.AddPragmaHandler("STDC", FPContractHandler.get()); | 
|  |  | 
|  | STDCFENVHandler = std::make_unique<PragmaSTDC_FENV_ACCESSHandler>(); | 
|  | PP.AddPragmaHandler("STDC", STDCFENVHandler.get()); | 
|  |  | 
|  | STDCCXLIMITHandler = std::make_unique<PragmaSTDC_CX_LIMITED_RANGEHandler>(); | 
|  | PP.AddPragmaHandler("STDC", STDCCXLIMITHandler.get()); | 
|  |  | 
|  | STDCUnknownHandler = std::make_unique<PragmaSTDC_UnknownHandler>(); | 
|  | PP.AddPragmaHandler("STDC", STDCUnknownHandler.get()); | 
|  |  | 
|  | PCSectionHandler = std::make_unique<PragmaClangSectionHandler>(Actions); | 
|  | PP.AddPragmaHandler("clang", PCSectionHandler.get()); | 
|  |  | 
|  | if (getLangOpts().OpenCL) { | 
|  | OpenCLExtensionHandler = std::make_unique<PragmaOpenCLExtensionHandler>(); | 
|  | PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); | 
|  |  | 
|  | PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); | 
|  | } | 
|  | if (getLangOpts().OpenMP) | 
|  | OpenMPHandler = std::make_unique<PragmaOpenMPHandler>(); | 
|  | else | 
|  | OpenMPHandler = std::make_unique<PragmaNoOpenMPHandler>(); | 
|  | PP.AddPragmaHandler(OpenMPHandler.get()); | 
|  |  | 
|  | if (getLangOpts().MicrosoftExt || | 
|  | getTargetInfo().getTriple().isOSBinFormatELF()) { | 
|  | MSCommentHandler = std::make_unique<PragmaCommentHandler>(Actions); | 
|  | PP.AddPragmaHandler(MSCommentHandler.get()); | 
|  | } | 
|  |  | 
|  | FloatControlHandler = std::make_unique<PragmaFloatControlHandler>(Actions); | 
|  | PP.AddPragmaHandler(FloatControlHandler.get()); | 
|  | if (getLangOpts().MicrosoftExt) { | 
|  | MSDetectMismatchHandler = | 
|  | std::make_unique<PragmaDetectMismatchHandler>(Actions); | 
|  | PP.AddPragmaHandler(MSDetectMismatchHandler.get()); | 
|  | MSPointersToMembers = std::make_unique<PragmaMSPointersToMembers>(); | 
|  | PP.AddPragmaHandler(MSPointersToMembers.get()); | 
|  | MSVtorDisp = std::make_unique<PragmaMSVtorDisp>(); | 
|  | PP.AddPragmaHandler(MSVtorDisp.get()); | 
|  | MSInitSeg = std::make_unique<PragmaMSPragma>("init_seg"); | 
|  | PP.AddPragmaHandler(MSInitSeg.get()); | 
|  | MSDataSeg = std::make_unique<PragmaMSPragma>("data_seg"); | 
|  | PP.AddPragmaHandler(MSDataSeg.get()); | 
|  | MSBSSSeg = std::make_unique<PragmaMSPragma>("bss_seg"); | 
|  | PP.AddPragmaHandler(MSBSSSeg.get()); | 
|  | MSConstSeg = std::make_unique<PragmaMSPragma>("const_seg"); | 
|  | PP.AddPragmaHandler(MSConstSeg.get()); | 
|  | MSCodeSeg = std::make_unique<PragmaMSPragma>("code_seg"); | 
|  | PP.AddPragmaHandler(MSCodeSeg.get()); | 
|  | MSSection = std::make_unique<PragmaMSPragma>("section"); | 
|  | PP.AddPragmaHandler(MSSection.get()); | 
|  | MSRuntimeChecks = std::make_unique<PragmaMSRuntimeChecksHandler>(); | 
|  | PP.AddPragmaHandler(MSRuntimeChecks.get()); | 
|  | MSIntrinsic = std::make_unique<PragmaMSIntrinsicHandler>(); | 
|  | PP.AddPragmaHandler(MSIntrinsic.get()); | 
|  | MSOptimize = std::make_unique<PragmaMSOptimizeHandler>(); | 
|  | PP.AddPragmaHandler(MSOptimize.get()); | 
|  | } | 
|  |  | 
|  | if (getLangOpts().CUDA) { | 
|  | CUDAForceHostDeviceHandler = | 
|  | std::make_unique<PragmaForceCUDAHostDeviceHandler>(Actions); | 
|  | PP.AddPragmaHandler("clang", CUDAForceHostDeviceHandler.get()); | 
|  | } | 
|  |  | 
|  | OptimizeHandler = std::make_unique<PragmaOptimizeHandler>(Actions); | 
|  | PP.AddPragmaHandler("clang", OptimizeHandler.get()); | 
|  |  | 
|  | LoopHintHandler = std::make_unique<PragmaLoopHintHandler>(); | 
|  | PP.AddPragmaHandler("clang", LoopHintHandler.get()); | 
|  |  | 
|  | UnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("unroll"); | 
|  | PP.AddPragmaHandler(UnrollHintHandler.get()); | 
|  |  | 
|  | NoUnrollHintHandler = std::make_unique<PragmaUnrollHintHandler>("nounroll"); | 
|  | PP.AddPragmaHandler(NoUnrollHintHandler.get()); | 
|  |  | 
|  | UnrollAndJamHintHandler = | 
|  | std::make_unique<PragmaUnrollHintHandler>("unroll_and_jam"); | 
|  | PP.AddPragmaHandler(UnrollAndJamHintHandler.get()); | 
|  |  | 
|  | NoUnrollAndJamHintHandler = | 
|  | std::make_unique<PragmaUnrollHintHandler>("nounroll_and_jam"); | 
|  | PP.AddPragmaHandler(NoUnrollAndJamHintHandler.get()); | 
|  |  | 
|  | FPHandler = std::make_unique<PragmaFPHandler>(); | 
|  | PP.AddPragmaHandler("clang", FPHandler.get()); | 
|  |  | 
|  | AttributePragmaHandler = | 
|  | std::make_unique<PragmaAttributeHandler>(AttrFactory); | 
|  | PP.AddPragmaHandler("clang", AttributePragmaHandler.get()); | 
|  |  | 
|  | MaxTokensHerePragmaHandler = std::make_unique<PragmaMaxTokensHereHandler>(); | 
|  | PP.AddPragmaHandler("clang", MaxTokensHerePragmaHandler.get()); | 
|  |  | 
|  | MaxTokensTotalPragmaHandler = std::make_unique<PragmaMaxTokensTotalHandler>(); | 
|  | PP.AddPragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | 
|  | } | 
|  |  | 
|  | void Parser::resetPragmaHandlers() { | 
|  | // Remove the pragma handlers we installed. | 
|  | PP.RemovePragmaHandler(AlignHandler.get()); | 
|  | AlignHandler.reset(); | 
|  | PP.RemovePragmaHandler("GCC", GCCVisibilityHandler.get()); | 
|  | GCCVisibilityHandler.reset(); | 
|  | PP.RemovePragmaHandler(OptionsHandler.get()); | 
|  | OptionsHandler.reset(); | 
|  | PP.RemovePragmaHandler(PackHandler.get()); | 
|  | PackHandler.reset(); | 
|  | PP.RemovePragmaHandler(MSStructHandler.get()); | 
|  | MSStructHandler.reset(); | 
|  | PP.RemovePragmaHandler(UnusedHandler.get()); | 
|  | UnusedHandler.reset(); | 
|  | PP.RemovePragmaHandler(WeakHandler.get()); | 
|  | WeakHandler.reset(); | 
|  | PP.RemovePragmaHandler(RedefineExtnameHandler.get()); | 
|  | RedefineExtnameHandler.reset(); | 
|  |  | 
|  | if (getLangOpts().OpenCL) { | 
|  | PP.RemovePragmaHandler("OPENCL", OpenCLExtensionHandler.get()); | 
|  | OpenCLExtensionHandler.reset(); | 
|  | PP.RemovePragmaHandler("OPENCL", FPContractHandler.get()); | 
|  | } | 
|  | PP.RemovePragmaHandler(OpenMPHandler.get()); | 
|  | OpenMPHandler.reset(); | 
|  |  | 
|  | if (getLangOpts().MicrosoftExt || | 
|  | getTargetInfo().getTriple().isOSBinFormatELF()) { | 
|  | PP.RemovePragmaHandler(MSCommentHandler.get()); | 
|  | MSCommentHandler.reset(); | 
|  | } | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", PCSectionHandler.get()); | 
|  | PCSectionHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler(FloatControlHandler.get()); | 
|  | FloatControlHandler.reset(); | 
|  | if (getLangOpts().MicrosoftExt) { | 
|  | PP.RemovePragmaHandler(MSDetectMismatchHandler.get()); | 
|  | MSDetectMismatchHandler.reset(); | 
|  | PP.RemovePragmaHandler(MSPointersToMembers.get()); | 
|  | MSPointersToMembers.reset(); | 
|  | PP.RemovePragmaHandler(MSVtorDisp.get()); | 
|  | MSVtorDisp.reset(); | 
|  | PP.RemovePragmaHandler(MSInitSeg.get()); | 
|  | MSInitSeg.reset(); | 
|  | PP.RemovePragmaHandler(MSDataSeg.get()); | 
|  | MSDataSeg.reset(); | 
|  | PP.RemovePragmaHandler(MSBSSSeg.get()); | 
|  | MSBSSSeg.reset(); | 
|  | PP.RemovePragmaHandler(MSConstSeg.get()); | 
|  | MSConstSeg.reset(); | 
|  | PP.RemovePragmaHandler(MSCodeSeg.get()); | 
|  | MSCodeSeg.reset(); | 
|  | PP.RemovePragmaHandler(MSSection.get()); | 
|  | MSSection.reset(); | 
|  | PP.RemovePragmaHandler(MSRuntimeChecks.get()); | 
|  | MSRuntimeChecks.reset(); | 
|  | PP.RemovePragmaHandler(MSIntrinsic.get()); | 
|  | MSIntrinsic.reset(); | 
|  | PP.RemovePragmaHandler(MSOptimize.get()); | 
|  | MSOptimize.reset(); | 
|  | } | 
|  |  | 
|  | if (getLangOpts().CUDA) { | 
|  | PP.RemovePragmaHandler("clang", CUDAForceHostDeviceHandler.get()); | 
|  | CUDAForceHostDeviceHandler.reset(); | 
|  | } | 
|  |  | 
|  | PP.RemovePragmaHandler("STDC", FPContractHandler.get()); | 
|  | FPContractHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("STDC", STDCFENVHandler.get()); | 
|  | STDCFENVHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("STDC", STDCCXLIMITHandler.get()); | 
|  | STDCCXLIMITHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("STDC", STDCUnknownHandler.get()); | 
|  | STDCUnknownHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", OptimizeHandler.get()); | 
|  | OptimizeHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", LoopHintHandler.get()); | 
|  | LoopHintHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler(UnrollHintHandler.get()); | 
|  | UnrollHintHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler(NoUnrollHintHandler.get()); | 
|  | NoUnrollHintHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler(UnrollAndJamHintHandler.get()); | 
|  | UnrollAndJamHintHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler(NoUnrollAndJamHintHandler.get()); | 
|  | NoUnrollAndJamHintHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", FPHandler.get()); | 
|  | FPHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", AttributePragmaHandler.get()); | 
|  | AttributePragmaHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", MaxTokensHerePragmaHandler.get()); | 
|  | MaxTokensHerePragmaHandler.reset(); | 
|  |  | 
|  | PP.RemovePragmaHandler("clang", MaxTokensTotalPragmaHandler.get()); | 
|  | MaxTokensTotalPragmaHandler.reset(); | 
|  | } | 
|  |  | 
|  | /// Handle the annotation token produced for #pragma unused(...) | 
|  | /// | 
|  | /// Each annot_pragma_unused is followed by the argument token so e.g. | 
|  | /// "#pragma unused(x,y)" becomes: | 
|  | /// annot_pragma_unused 'x' annot_pragma_unused 'y' | 
|  | void Parser::HandlePragmaUnused() { | 
|  | assert(Tok.is(tok::annot_pragma_unused)); | 
|  | SourceLocation UnusedLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaUnused(Tok, getCurScope(), UnusedLoc); | 
|  | ConsumeToken(); // The argument token. | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaVisibility() { | 
|  | assert(Tok.is(tok::annot_pragma_vis)); | 
|  | const IdentifierInfo *VisType = | 
|  | static_cast<IdentifierInfo *>(Tok.getAnnotationValue()); | 
|  | SourceLocation VisLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaVisibility(VisType, VisLoc); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | struct PragmaPackInfo { | 
|  | Sema::PragmaMsStackAction Action; | 
|  | StringRef SlotLabel; | 
|  | Token Alignment; | 
|  | }; | 
|  | } // end anonymous namespace | 
|  |  | 
|  | void Parser::HandlePragmaPack() { | 
|  | assert(Tok.is(tok::annot_pragma_pack)); | 
|  | PragmaPackInfo *Info = | 
|  | static_cast<PragmaPackInfo *>(Tok.getAnnotationValue()); | 
|  | SourceLocation PragmaLoc = Tok.getLocation(); | 
|  | ExprResult Alignment; | 
|  | if (Info->Alignment.is(tok::numeric_constant)) { | 
|  | Alignment = Actions.ActOnNumericConstant(Info->Alignment); | 
|  | if (Alignment.isInvalid()) { | 
|  | ConsumeAnnotationToken(); | 
|  | return; | 
|  | } | 
|  | } | 
|  | Actions.ActOnPragmaPack(PragmaLoc, Info->Action, Info->SlotLabel, | 
|  | Alignment.get()); | 
|  | // Consume the token after processing the pragma to enable pragma-specific | 
|  | // #include warnings. | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaMSStruct() { | 
|  | assert(Tok.is(tok::annot_pragma_msstruct)); | 
|  | PragmaMSStructKind Kind = static_cast<PragmaMSStructKind>( | 
|  | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | 
|  | Actions.ActOnPragmaMSStruct(Kind); | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaAlign() { | 
|  | assert(Tok.is(tok::annot_pragma_align)); | 
|  | Sema::PragmaOptionsAlignKind Kind = | 
|  | static_cast<Sema::PragmaOptionsAlignKind>( | 
|  | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | 
|  | Actions.ActOnPragmaOptionsAlign(Kind, Tok.getLocation()); | 
|  | // Consume the token after processing the pragma to enable pragma-specific | 
|  | // #include warnings. | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaDump() { | 
|  | assert(Tok.is(tok::annot_pragma_dump)); | 
|  | IdentifierInfo *II = | 
|  | reinterpret_cast<IdentifierInfo *>(Tok.getAnnotationValue()); | 
|  | Actions.ActOnPragmaDump(getCurScope(), Tok.getLocation(), II); | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaWeak() { | 
|  | assert(Tok.is(tok::annot_pragma_weak)); | 
|  | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc, | 
|  | Tok.getLocation()); | 
|  | ConsumeToken(); // The weak name. | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaWeakAlias() { | 
|  | assert(Tok.is(tok::annot_pragma_weakalias)); | 
|  | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | 
|  | IdentifierInfo *WeakName = Tok.getIdentifierInfo(); | 
|  | SourceLocation WeakNameLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | IdentifierInfo *AliasName = Tok.getIdentifierInfo(); | 
|  | SourceLocation AliasNameLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc, | 
|  | WeakNameLoc, AliasNameLoc); | 
|  |  | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaRedefineExtname() { | 
|  | assert(Tok.is(tok::annot_pragma_redefine_extname)); | 
|  | SourceLocation RedefLoc = ConsumeAnnotationToken(); | 
|  | IdentifierInfo *RedefName = Tok.getIdentifierInfo(); | 
|  | SourceLocation RedefNameLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | IdentifierInfo *AliasName = Tok.getIdentifierInfo(); | 
|  | SourceLocation AliasNameLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, | 
|  | RedefNameLoc, AliasNameLoc); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaFPContract() { | 
|  | assert(Tok.is(tok::annot_pragma_fp_contract)); | 
|  | tok::OnOffSwitch OOS = | 
|  | static_cast<tok::OnOffSwitch>( | 
|  | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | 
|  |  | 
|  | LangOptions::FPModeKind FPC; | 
|  | switch (OOS) { | 
|  | case tok::OOS_ON: | 
|  | FPC = LangOptions::FPM_On; | 
|  | break; | 
|  | case tok::OOS_OFF: | 
|  | FPC = LangOptions::FPM_Off; | 
|  | break; | 
|  | case tok::OOS_DEFAULT: | 
|  | FPC = getLangOpts().getDefaultFPContractMode(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | Actions.ActOnPragmaFPContract(FPC); | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaFloatControl() { | 
|  | assert(Tok.is(tok::annot_pragma_float_control)); | 
|  |  | 
|  | // The value that is held on the PragmaFloatControlStack encodes | 
|  | // the PragmaFloatControl kind and the MSStackAction kind | 
|  | // into a single 32-bit word. The MsStackAction is the high 16 bits | 
|  | // and the FloatControl is the lower 16 bits. Use shift and bit-and | 
|  | // to decode the parts. | 
|  | uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); | 
|  | Sema::PragmaMsStackAction Action = | 
|  | static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); | 
|  | PragmaFloatControlKind Kind = PragmaFloatControlKind(Value & 0xFFFF); | 
|  | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaFloatControl(PragmaLoc, Action, Kind); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaFEnvAccess() { | 
|  | assert(Tok.is(tok::annot_pragma_fenv_access)); | 
|  | tok::OnOffSwitch OOS = | 
|  | static_cast<tok::OnOffSwitch>( | 
|  | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | 
|  |  | 
|  | bool IsEnabled; | 
|  | switch (OOS) { | 
|  | case tok::OOS_ON: | 
|  | IsEnabled = true; | 
|  | break; | 
|  | case tok::OOS_OFF: | 
|  | IsEnabled = false; | 
|  | break; | 
|  | case tok::OOS_DEFAULT: // FIXME: Add this cli option when it makes sense. | 
|  | IsEnabled = false; | 
|  | break; | 
|  | } | 
|  |  | 
|  | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaFEnvAccess(PragmaLoc, IsEnabled); | 
|  | } | 
|  |  | 
|  |  | 
|  | StmtResult Parser::HandlePragmaCaptured() | 
|  | { | 
|  | assert(Tok.is(tok::annot_pragma_captured)); | 
|  | ConsumeAnnotationToken(); | 
|  |  | 
|  | if (Tok.isNot(tok::l_brace)) { | 
|  | PP.Diag(Tok, diag::err_expected) << tok::l_brace; | 
|  | return StmtError(); | 
|  | } | 
|  |  | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  |  | 
|  | ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope | | 
|  | Scope::CompoundStmtScope); | 
|  | Actions.ActOnCapturedRegionStart(Loc, getCurScope(), CR_Default, | 
|  | /*NumParams=*/1); | 
|  |  | 
|  | StmtResult R = ParseCompoundStatement(); | 
|  | CapturedRegionScope.Exit(); | 
|  |  | 
|  | if (R.isInvalid()) { | 
|  | Actions.ActOnCapturedRegionError(); | 
|  | return StmtError(); | 
|  | } | 
|  |  | 
|  | return Actions.ActOnCapturedRegionEnd(R.get()); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | enum OpenCLExtState : char { | 
|  | Disable, Enable, Begin, End | 
|  | }; | 
|  | typedef std::pair<const IdentifierInfo *, OpenCLExtState> OpenCLExtData; | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaOpenCLExtension() { | 
|  | assert(Tok.is(tok::annot_pragma_opencl_extension)); | 
|  | OpenCLExtData *Data = static_cast<OpenCLExtData*>(Tok.getAnnotationValue()); | 
|  | auto State = Data->second; | 
|  | auto Ident = Data->first; | 
|  | SourceLocation NameLoc = Tok.getLocation(); | 
|  | ConsumeAnnotationToken(); | 
|  |  | 
|  | auto &Opt = Actions.getOpenCLOptions(); | 
|  | auto Name = Ident->getName(); | 
|  | // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, | 
|  | // overriding all previously issued extension directives, but only if the | 
|  | // behavior is set to disable." | 
|  | if (Name == "all") { | 
|  | if (State == Disable) { | 
|  | Opt.disableAll(); | 
|  | Opt.enableSupportedCore(getLangOpts()); | 
|  | } else { | 
|  | PP.Diag(NameLoc, diag::warn_pragma_expected_predicate) << 1; | 
|  | } | 
|  | } else if (State == Begin) { | 
|  | if (!Opt.isKnown(Name) || !Opt.isSupported(Name, getLangOpts())) { | 
|  | Opt.support(Name); | 
|  | } | 
|  | Actions.setCurrentOpenCLExtension(Name); | 
|  | } else if (State == End) { | 
|  | if (Name != Actions.getCurrentOpenCLExtension()) | 
|  | PP.Diag(NameLoc, diag::warn_pragma_begin_end_mismatch); | 
|  | Actions.setCurrentOpenCLExtension(""); | 
|  | } else if (!Opt.isKnown(Name)) | 
|  | PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << Ident; | 
|  | else if (Opt.isSupportedExtension(Name, getLangOpts())) | 
|  | Opt.enable(Name, State == Enable); | 
|  | else if (Opt.isSupportedCore(Name, getLangOpts())) | 
|  | PP.Diag(NameLoc, diag::warn_pragma_extension_is_core) << Ident; | 
|  | else | 
|  | PP.Diag(NameLoc, diag::warn_pragma_unsupported_extension) << Ident; | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaMSPointersToMembers() { | 
|  | assert(Tok.is(tok::annot_pragma_ms_pointers_to_members)); | 
|  | LangOptions::PragmaMSPointersToMembersKind RepresentationMethod = | 
|  | static_cast<LangOptions::PragmaMSPointersToMembersKind>( | 
|  | reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); | 
|  | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaMSPointersToMembers(RepresentationMethod, PragmaLoc); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaMSVtorDisp() { | 
|  | assert(Tok.is(tok::annot_pragma_ms_vtordisp)); | 
|  | uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); | 
|  | Sema::PragmaMsStackAction Action = | 
|  | static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); | 
|  | MSVtorDispMode Mode = MSVtorDispMode(Value & 0xFFFF); | 
|  | SourceLocation PragmaLoc = ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaMSPragma() { | 
|  | assert(Tok.is(tok::annot_pragma_ms_pragma)); | 
|  | // Grab the tokens out of the annotation and enter them into the stream. | 
|  | auto TheTokens = | 
|  | (std::pair<std::unique_ptr<Token[]>, size_t> *)Tok.getAnnotationValue(); | 
|  | PP.EnterTokenStream(std::move(TheTokens->first), TheTokens->second, true, | 
|  | /*IsReinject=*/true); | 
|  | SourceLocation PragmaLocation = ConsumeAnnotationToken(); | 
|  | assert(Tok.isAnyIdentifier()); | 
|  | StringRef PragmaName = Tok.getIdentifierInfo()->getName(); | 
|  | PP.Lex(Tok); // pragma kind | 
|  |  | 
|  | // Figure out which #pragma we're dealing with.  The switch has no default | 
|  | // because lex shouldn't emit the annotation token for unrecognized pragmas. | 
|  | typedef bool (Parser::*PragmaHandler)(StringRef, SourceLocation); | 
|  | PragmaHandler Handler = llvm::StringSwitch<PragmaHandler>(PragmaName) | 
|  | .Case("data_seg", &Parser::HandlePragmaMSSegment) | 
|  | .Case("bss_seg", &Parser::HandlePragmaMSSegment) | 
|  | .Case("const_seg", &Parser::HandlePragmaMSSegment) | 
|  | .Case("code_seg", &Parser::HandlePragmaMSSegment) | 
|  | .Case("section", &Parser::HandlePragmaMSSection) | 
|  | .Case("init_seg", &Parser::HandlePragmaMSInitSeg); | 
|  |  | 
|  | if (!(this->*Handler)(PragmaName, PragmaLocation)) { | 
|  | // Pragma handling failed, and has been diagnosed.  Slurp up the tokens | 
|  | // until eof (really end of line) to prevent follow-on errors. | 
|  | while (Tok.isNot(tok::eof)) | 
|  | PP.Lex(Tok); | 
|  | PP.Lex(Tok); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Parser::HandlePragmaMSSection(StringRef PragmaName, | 
|  | SourceLocation PragmaLocation) { | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName; | 
|  | return false; | 
|  | } | 
|  | PP.Lex(Tok); // ( | 
|  | // Parsing code for pragma section | 
|  | if (Tok.isNot(tok::string_literal)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_section_name) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | ExprResult StringResult = ParseStringLiteralExpression(); | 
|  | if (StringResult.isInvalid()) | 
|  | return false; // Already diagnosed. | 
|  | StringLiteral *SegmentName = cast<StringLiteral>(StringResult.get()); | 
|  | if (SegmentName->getCharByteWidth() != 1) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | int SectionFlags = ASTContext::PSF_Read; | 
|  | bool SectionFlagsAreDefault = true; | 
|  | while (Tok.is(tok::comma)) { | 
|  | PP.Lex(Tok); // , | 
|  | // Ignore "long" and "short". | 
|  | // They are undocumented, but widely used, section attributes which appear | 
|  | // to do nothing. | 
|  | if (Tok.is(tok::kw_long) || Tok.is(tok::kw_short)) { | 
|  | PP.Lex(Tok); // long/short | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (!Tok.isAnyIdentifier()) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | ASTContext::PragmaSectionFlag Flag = | 
|  | llvm::StringSwitch<ASTContext::PragmaSectionFlag>( | 
|  | Tok.getIdentifierInfo()->getName()) | 
|  | .Case("read", ASTContext::PSF_Read) | 
|  | .Case("write", ASTContext::PSF_Write) | 
|  | .Case("execute", ASTContext::PSF_Execute) | 
|  | .Case("shared", ASTContext::PSF_Invalid) | 
|  | .Case("nopage", ASTContext::PSF_Invalid) | 
|  | .Case("nocache", ASTContext::PSF_Invalid) | 
|  | .Case("discard", ASTContext::PSF_Invalid) | 
|  | .Case("remove", ASTContext::PSF_Invalid) | 
|  | .Default(ASTContext::PSF_None); | 
|  | if (Flag == ASTContext::PSF_None || Flag == ASTContext::PSF_Invalid) { | 
|  | PP.Diag(PragmaLocation, Flag == ASTContext::PSF_None | 
|  | ? diag::warn_pragma_invalid_specific_action | 
|  | : diag::warn_pragma_unsupported_action) | 
|  | << PragmaName << Tok.getIdentifierInfo()->getName(); | 
|  | return false; | 
|  | } | 
|  | SectionFlags |= Flag; | 
|  | SectionFlagsAreDefault = false; | 
|  | PP.Lex(Tok); // Identifier | 
|  | } | 
|  | // If no section attributes are specified, the section will be marked as | 
|  | // read/write. | 
|  | if (SectionFlagsAreDefault) | 
|  | SectionFlags |= ASTContext::PSF_Write; | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName; | 
|  | return false; | 
|  | } | 
|  | PP.Lex(Tok); // ) | 
|  | if (Tok.isNot(tok::eof)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | PP.Lex(Tok); // eof | 
|  | Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Parser::HandlePragmaMSSegment(StringRef PragmaName, | 
|  | SourceLocation PragmaLocation) { | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_lparen) << PragmaName; | 
|  | return false; | 
|  | } | 
|  | PP.Lex(Tok); // ( | 
|  | Sema::PragmaMsStackAction Action = Sema::PSK_Reset; | 
|  | StringRef SlotLabel; | 
|  | if (Tok.isAnyIdentifier()) { | 
|  | StringRef PushPop = Tok.getIdentifierInfo()->getName(); | 
|  | if (PushPop == "push") | 
|  | Action = Sema::PSK_Push; | 
|  | else if (PushPop == "pop") | 
|  | Action = Sema::PSK_Pop; | 
|  | else { | 
|  | PP.Diag(PragmaLocation, | 
|  | diag::warn_pragma_expected_section_push_pop_or_name) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | if (Action != Sema::PSK_Reset) { | 
|  | PP.Lex(Tok); // push | pop | 
|  | if (Tok.is(tok::comma)) { | 
|  | PP.Lex(Tok); // , | 
|  | // If we've got a comma, we either need a label or a string. | 
|  | if (Tok.isAnyIdentifier()) { | 
|  | SlotLabel = Tok.getIdentifierInfo()->getName(); | 
|  | PP.Lex(Tok); // identifier | 
|  | if (Tok.is(tok::comma)) | 
|  | PP.Lex(Tok); | 
|  | else if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } else if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_punc) << PragmaName; | 
|  | return false; | 
|  | } | 
|  | } | 
|  | } | 
|  | // Grab the string literal for our section name. | 
|  | StringLiteral *SegmentName = nullptr; | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | if (Tok.isNot(tok::string_literal)) { | 
|  | unsigned DiagID = Action != Sema::PSK_Reset ? !SlotLabel.empty() ? | 
|  | diag::warn_pragma_expected_section_name : | 
|  | diag::warn_pragma_expected_section_label_or_name : | 
|  | diag::warn_pragma_expected_section_push_pop_or_name; | 
|  | PP.Diag(PragmaLocation, DiagID) << PragmaName; | 
|  | return false; | 
|  | } | 
|  | ExprResult StringResult = ParseStringLiteralExpression(); | 
|  | if (StringResult.isInvalid()) | 
|  | return false; // Already diagnosed. | 
|  | SegmentName = cast<StringLiteral>(StringResult.get()); | 
|  | if (SegmentName->getCharByteWidth() != 1) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | // Setting section "" has no effect | 
|  | if (SegmentName->getLength()) | 
|  | Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); | 
|  | } | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_rparen) << PragmaName; | 
|  | return false; | 
|  | } | 
|  | PP.Lex(Tok); // ) | 
|  | if (Tok.isNot(tok::eof)) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_extra_tokens_at_eol) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | PP.Lex(Tok); // eof | 
|  | Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel, | 
|  | SegmentName, PragmaName); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // #pragma init_seg({ compiler | lib | user | "section-name" [, func-name]} ) | 
|  | bool Parser::HandlePragmaMSInitSeg(StringRef PragmaName, | 
|  | SourceLocation PragmaLocation) { | 
|  | if (getTargetInfo().getTriple().getEnvironment() != llvm::Triple::MSVC) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_init_seg_unsupported_target); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (ExpectAndConsume(tok::l_paren, diag::warn_pragma_expected_lparen, | 
|  | PragmaName)) | 
|  | return false; | 
|  |  | 
|  | // Parse either the known section names or the string section name. | 
|  | StringLiteral *SegmentName = nullptr; | 
|  | if (Tok.isAnyIdentifier()) { | 
|  | auto *II = Tok.getIdentifierInfo(); | 
|  | StringRef Section = llvm::StringSwitch<StringRef>(II->getName()) | 
|  | .Case("compiler", "\".CRT$XCC\"") | 
|  | .Case("lib", "\".CRT$XCL\"") | 
|  | .Case("user", "\".CRT$XCU\"") | 
|  | .Default(""); | 
|  |  | 
|  | if (!Section.empty()) { | 
|  | // Pretend the user wrote the appropriate string literal here. | 
|  | Token Toks[1]; | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::string_literal); | 
|  | Toks[0].setLocation(Tok.getLocation()); | 
|  | Toks[0].setLiteralData(Section.data()); | 
|  | Toks[0].setLength(Section.size()); | 
|  | SegmentName = | 
|  | cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get()); | 
|  | PP.Lex(Tok); | 
|  | } | 
|  | } else if (Tok.is(tok::string_literal)) { | 
|  | ExprResult StringResult = ParseStringLiteralExpression(); | 
|  | if (StringResult.isInvalid()) | 
|  | return false; | 
|  | SegmentName = cast<StringLiteral>(StringResult.get()); | 
|  | if (SegmentName->getCharByteWidth() != 1) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_non_wide_string) | 
|  | << PragmaName; | 
|  | return false; | 
|  | } | 
|  | // FIXME: Add support for the '[, func-name]' part of the pragma. | 
|  | } | 
|  |  | 
|  | if (!SegmentName) { | 
|  | PP.Diag(PragmaLocation, diag::warn_pragma_expected_init_seg) << PragmaName; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (ExpectAndConsume(tok::r_paren, diag::warn_pragma_expected_rparen, | 
|  | PragmaName) || | 
|  | ExpectAndConsume(tok::eof, diag::warn_pragma_extra_tokens_at_eol, | 
|  | PragmaName)) | 
|  | return false; | 
|  |  | 
|  | Actions.ActOnPragmaMSInitSeg(PragmaLocation, SegmentName); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | struct PragmaLoopHintInfo { | 
|  | Token PragmaName; | 
|  | Token Option; | 
|  | ArrayRef<Token> Toks; | 
|  | }; | 
|  | } // end anonymous namespace | 
|  |  | 
|  | static std::string PragmaLoopHintString(Token PragmaName, Token Option) { | 
|  | StringRef Str = PragmaName.getIdentifierInfo()->getName(); | 
|  | std::string ClangLoopStr = (llvm::Twine("clang loop ") + Str).str(); | 
|  | return std::string(llvm::StringSwitch<StringRef>(Str) | 
|  | .Case("loop", ClangLoopStr) | 
|  | .Case("unroll_and_jam", Str) | 
|  | .Case("unroll", Str) | 
|  | .Default("")); | 
|  | } | 
|  |  | 
|  | bool Parser::HandlePragmaLoopHint(LoopHint &Hint) { | 
|  | assert(Tok.is(tok::annot_pragma_loop_hint)); | 
|  | PragmaLoopHintInfo *Info = | 
|  | static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue()); | 
|  |  | 
|  | IdentifierInfo *PragmaNameInfo = Info->PragmaName.getIdentifierInfo(); | 
|  | Hint.PragmaNameLoc = IdentifierLoc::create( | 
|  | Actions.Context, Info->PragmaName.getLocation(), PragmaNameInfo); | 
|  |  | 
|  | // It is possible that the loop hint has no option identifier, such as | 
|  | // #pragma unroll(4). | 
|  | IdentifierInfo *OptionInfo = Info->Option.is(tok::identifier) | 
|  | ? Info->Option.getIdentifierInfo() | 
|  | : nullptr; | 
|  | Hint.OptionLoc = IdentifierLoc::create( | 
|  | Actions.Context, Info->Option.getLocation(), OptionInfo); | 
|  |  | 
|  | llvm::ArrayRef<Token> Toks = Info->Toks; | 
|  |  | 
|  | // Return a valid hint if pragma unroll or nounroll were specified | 
|  | // without an argument. | 
|  | auto IsLoopHint = llvm::StringSwitch<bool>(PragmaNameInfo->getName()) | 
|  | .Cases("unroll", "nounroll", "unroll_and_jam", | 
|  | "nounroll_and_jam", true) | 
|  | .Default(false); | 
|  |  | 
|  | if (Toks.empty() && IsLoopHint) { | 
|  | ConsumeAnnotationToken(); | 
|  | Hint.Range = Info->PragmaName.getLocation(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // The constant expression is always followed by an eof token, which increases | 
|  | // the TokSize by 1. | 
|  | assert(!Toks.empty() && | 
|  | "PragmaLoopHintInfo::Toks must contain at least one token."); | 
|  |  | 
|  | // If no option is specified the argument is assumed to be a constant expr. | 
|  | bool OptionUnroll = false; | 
|  | bool OptionUnrollAndJam = false; | 
|  | bool OptionDistribute = false; | 
|  | bool OptionPipelineDisabled = false; | 
|  | bool StateOption = false; | 
|  | if (OptionInfo) { // Pragma Unroll does not specify an option. | 
|  | OptionUnroll = OptionInfo->isStr("unroll"); | 
|  | OptionUnrollAndJam = OptionInfo->isStr("unroll_and_jam"); | 
|  | OptionDistribute = OptionInfo->isStr("distribute"); | 
|  | OptionPipelineDisabled = OptionInfo->isStr("pipeline"); | 
|  | StateOption = llvm::StringSwitch<bool>(OptionInfo->getName()) | 
|  | .Case("vectorize", true) | 
|  | .Case("interleave", true) | 
|  | .Case("vectorize_predicate", true) | 
|  | .Default(false) || | 
|  | OptionUnroll || OptionUnrollAndJam || OptionDistribute || | 
|  | OptionPipelineDisabled; | 
|  | } | 
|  |  | 
|  | bool AssumeSafetyArg = !OptionUnroll && !OptionUnrollAndJam && | 
|  | !OptionDistribute && !OptionPipelineDisabled; | 
|  | // Verify loop hint has an argument. | 
|  | if (Toks[0].is(tok::eof)) { | 
|  | ConsumeAnnotationToken(); | 
|  | Diag(Toks[0].getLocation(), diag::err_pragma_loop_missing_argument) | 
|  | << /*StateArgument=*/StateOption | 
|  | << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam) | 
|  | << /*AssumeSafetyKeyword=*/AssumeSafetyArg; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Validate the argument. | 
|  | if (StateOption) { | 
|  | ConsumeAnnotationToken(); | 
|  | SourceLocation StateLoc = Toks[0].getLocation(); | 
|  | IdentifierInfo *StateInfo = Toks[0].getIdentifierInfo(); | 
|  |  | 
|  | bool Valid = StateInfo && | 
|  | llvm::StringSwitch<bool>(StateInfo->getName()) | 
|  | .Case("disable", true) | 
|  | .Case("enable", !OptionPipelineDisabled) | 
|  | .Case("full", OptionUnroll || OptionUnrollAndJam) | 
|  | .Case("assume_safety", AssumeSafetyArg) | 
|  | .Default(false); | 
|  | if (!Valid) { | 
|  | if (OptionPipelineDisabled) { | 
|  | Diag(Toks[0].getLocation(), diag::err_pragma_pipeline_invalid_keyword); | 
|  | } else { | 
|  | Diag(Toks[0].getLocation(), diag::err_pragma_invalid_keyword) | 
|  | << /*FullKeyword=*/(OptionUnroll || OptionUnrollAndJam) | 
|  | << /*AssumeSafetyKeyword=*/AssumeSafetyArg; | 
|  | } | 
|  | return false; | 
|  | } | 
|  | if (Toks.size() > 2) | 
|  | Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << PragmaLoopHintString(Info->PragmaName, Info->Option); | 
|  | Hint.StateLoc = IdentifierLoc::create(Actions.Context, StateLoc, StateInfo); | 
|  | } else { | 
|  | // Enter constant expression including eof terminator into token stream. | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/false, | 
|  | /*IsReinject=*/false); | 
|  | ConsumeAnnotationToken(); | 
|  |  | 
|  | ExprResult R = ParseConstantExpression(); | 
|  |  | 
|  | // Tokens following an error in an ill-formed constant expression will | 
|  | // remain in the token stream and must be removed. | 
|  | if (Tok.isNot(tok::eof)) { | 
|  | Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << PragmaLoopHintString(Info->PragmaName, Info->Option); | 
|  | while (Tok.isNot(tok::eof)) | 
|  | ConsumeAnyToken(); | 
|  | } | 
|  |  | 
|  | ConsumeToken(); // Consume the constant expression eof terminator. | 
|  |  | 
|  | if (R.isInvalid() || | 
|  | Actions.CheckLoopHintExpr(R.get(), Toks[0].getLocation())) | 
|  | return false; | 
|  |  | 
|  | // Argument is a constant expression with an integer type. | 
|  | Hint.ValueExpr = R.get(); | 
|  | } | 
|  |  | 
|  | Hint.Range = SourceRange(Info->PragmaName.getLocation(), | 
|  | Info->Toks.back().getLocation()); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | struct PragmaAttributeInfo { | 
|  | enum ActionType { Push, Pop, Attribute }; | 
|  | ParsedAttributes &Attributes; | 
|  | ActionType Action; | 
|  | const IdentifierInfo *Namespace = nullptr; | 
|  | ArrayRef<Token> Tokens; | 
|  |  | 
|  | PragmaAttributeInfo(ParsedAttributes &Attributes) : Attributes(Attributes) {} | 
|  | }; | 
|  |  | 
|  | #include "clang/Parse/AttrSubMatchRulesParserStringSwitches.inc" | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | static StringRef getIdentifier(const Token &Tok) { | 
|  | if (Tok.is(tok::identifier)) | 
|  | return Tok.getIdentifierInfo()->getName(); | 
|  | const char *S = tok::getKeywordSpelling(Tok.getKind()); | 
|  | if (!S) | 
|  | return ""; | 
|  | return S; | 
|  | } | 
|  |  | 
|  | static bool isAbstractAttrMatcherRule(attr::SubjectMatchRule Rule) { | 
|  | using namespace attr; | 
|  | switch (Rule) { | 
|  | #define ATTR_MATCH_RULE(Value, Spelling, IsAbstract)                           \ | 
|  | case Value:                                                                  \ | 
|  | return IsAbstract; | 
|  | #include "clang/Basic/AttrSubMatchRulesList.inc" | 
|  | } | 
|  | llvm_unreachable("Invalid attribute subject match rule"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | static void diagnoseExpectedAttributeSubjectSubRule( | 
|  | Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName, | 
|  | SourceLocation SubRuleLoc) { | 
|  | auto Diagnostic = | 
|  | PRef.Diag(SubRuleLoc, | 
|  | diag::err_pragma_attribute_expected_subject_sub_identifier) | 
|  | << PrimaryRuleName; | 
|  | if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule)) | 
|  | Diagnostic << /*SubRulesSupported=*/1 << SubRules; | 
|  | else | 
|  | Diagnostic << /*SubRulesSupported=*/0; | 
|  | } | 
|  |  | 
|  | static void diagnoseUnknownAttributeSubjectSubRule( | 
|  | Parser &PRef, attr::SubjectMatchRule PrimaryRule, StringRef PrimaryRuleName, | 
|  | StringRef SubRuleName, SourceLocation SubRuleLoc) { | 
|  |  | 
|  | auto Diagnostic = | 
|  | PRef.Diag(SubRuleLoc, diag::err_pragma_attribute_unknown_subject_sub_rule) | 
|  | << SubRuleName << PrimaryRuleName; | 
|  | if (const char *SubRules = validAttributeSubjectMatchSubRules(PrimaryRule)) | 
|  | Diagnostic << /*SubRulesSupported=*/1 << SubRules; | 
|  | else | 
|  | Diagnostic << /*SubRulesSupported=*/0; | 
|  | } | 
|  |  | 
|  | bool Parser::ParsePragmaAttributeSubjectMatchRuleSet( | 
|  | attr::ParsedSubjectMatchRuleSet &SubjectMatchRules, SourceLocation &AnyLoc, | 
|  | SourceLocation &LastMatchRuleEndLoc) { | 
|  | bool IsAny = false; | 
|  | BalancedDelimiterTracker AnyParens(*this, tok::l_paren); | 
|  | if (getIdentifier(Tok) == "any") { | 
|  | AnyLoc = ConsumeToken(); | 
|  | IsAny = true; | 
|  | if (AnyParens.expectAndConsume()) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | do { | 
|  | // Parse the subject matcher rule. | 
|  | StringRef Name = getIdentifier(Tok); | 
|  | if (Name.empty()) { | 
|  | Diag(Tok, diag::err_pragma_attribute_expected_subject_identifier); | 
|  | return true; | 
|  | } | 
|  | std::pair<Optional<attr::SubjectMatchRule>, | 
|  | Optional<attr::SubjectMatchRule> (*)(StringRef, bool)> | 
|  | Rule = isAttributeSubjectMatchRule(Name); | 
|  | if (!Rule.first) { | 
|  | Diag(Tok, diag::err_pragma_attribute_unknown_subject_rule) << Name; | 
|  | return true; | 
|  | } | 
|  | attr::SubjectMatchRule PrimaryRule = *Rule.first; | 
|  | SourceLocation RuleLoc = ConsumeToken(); | 
|  |  | 
|  | BalancedDelimiterTracker Parens(*this, tok::l_paren); | 
|  | if (isAbstractAttrMatcherRule(PrimaryRule)) { | 
|  | if (Parens.expectAndConsume()) | 
|  | return true; | 
|  | } else if (Parens.consumeOpen()) { | 
|  | if (!SubjectMatchRules | 
|  | .insert( | 
|  | std::make_pair(PrimaryRule, SourceRange(RuleLoc, RuleLoc))) | 
|  | .second) | 
|  | Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject) | 
|  | << Name | 
|  | << FixItHint::CreateRemoval(SourceRange( | 
|  | RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleLoc)); | 
|  | LastMatchRuleEndLoc = RuleLoc; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Parse the sub-rules. | 
|  | StringRef SubRuleName = getIdentifier(Tok); | 
|  | if (SubRuleName.empty()) { | 
|  | diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name, | 
|  | Tok.getLocation()); | 
|  | return true; | 
|  | } | 
|  | attr::SubjectMatchRule SubRule; | 
|  | if (SubRuleName == "unless") { | 
|  | SourceLocation SubRuleLoc = ConsumeToken(); | 
|  | BalancedDelimiterTracker Parens(*this, tok::l_paren); | 
|  | if (Parens.expectAndConsume()) | 
|  | return true; | 
|  | SubRuleName = getIdentifier(Tok); | 
|  | if (SubRuleName.empty()) { | 
|  | diagnoseExpectedAttributeSubjectSubRule(*this, PrimaryRule, Name, | 
|  | SubRuleLoc); | 
|  | return true; | 
|  | } | 
|  | auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/true); | 
|  | if (!SubRuleOrNone) { | 
|  | std::string SubRuleUnlessName = "unless(" + SubRuleName.str() + ")"; | 
|  | diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name, | 
|  | SubRuleUnlessName, SubRuleLoc); | 
|  | return true; | 
|  | } | 
|  | SubRule = *SubRuleOrNone; | 
|  | ConsumeToken(); | 
|  | if (Parens.consumeClose()) | 
|  | return true; | 
|  | } else { | 
|  | auto SubRuleOrNone = Rule.second(SubRuleName, /*IsUnless=*/false); | 
|  | if (!SubRuleOrNone) { | 
|  | diagnoseUnknownAttributeSubjectSubRule(*this, PrimaryRule, Name, | 
|  | SubRuleName, Tok.getLocation()); | 
|  | return true; | 
|  | } | 
|  | SubRule = *SubRuleOrNone; | 
|  | ConsumeToken(); | 
|  | } | 
|  | SourceLocation RuleEndLoc = Tok.getLocation(); | 
|  | LastMatchRuleEndLoc = RuleEndLoc; | 
|  | if (Parens.consumeClose()) | 
|  | return true; | 
|  | if (!SubjectMatchRules | 
|  | .insert(std::make_pair(SubRule, SourceRange(RuleLoc, RuleEndLoc))) | 
|  | .second) { | 
|  | Diag(RuleLoc, diag::err_pragma_attribute_duplicate_subject) | 
|  | << attr::getSubjectMatchRuleSpelling(SubRule) | 
|  | << FixItHint::CreateRemoval(SourceRange( | 
|  | RuleLoc, Tok.is(tok::comma) ? Tok.getLocation() : RuleEndLoc)); | 
|  | continue; | 
|  | } | 
|  | } while (IsAny && TryConsumeToken(tok::comma)); | 
|  |  | 
|  | if (IsAny) | 
|  | if (AnyParens.consumeClose()) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | /// Describes the stage at which attribute subject rule parsing was interrupted. | 
|  | enum class MissingAttributeSubjectRulesRecoveryPoint { | 
|  | Comma, | 
|  | ApplyTo, | 
|  | Equals, | 
|  | Any, | 
|  | None, | 
|  | }; | 
|  |  | 
|  | MissingAttributeSubjectRulesRecoveryPoint | 
|  | getAttributeSubjectRulesRecoveryPointForToken(const Token &Tok) { | 
|  | if (const auto *II = Tok.getIdentifierInfo()) { | 
|  | if (II->isStr("apply_to")) | 
|  | return MissingAttributeSubjectRulesRecoveryPoint::ApplyTo; | 
|  | if (II->isStr("any")) | 
|  | return MissingAttributeSubjectRulesRecoveryPoint::Any; | 
|  | } | 
|  | if (Tok.is(tok::equal)) | 
|  | return MissingAttributeSubjectRulesRecoveryPoint::Equals; | 
|  | return MissingAttributeSubjectRulesRecoveryPoint::None; | 
|  | } | 
|  |  | 
|  | /// Creates a diagnostic for the attribute subject rule parsing diagnostic that | 
|  | /// suggests the possible attribute subject rules in a fix-it together with | 
|  | /// any other missing tokens. | 
|  | DiagnosticBuilder createExpectedAttributeSubjectRulesTokenDiagnostic( | 
|  | unsigned DiagID, ParsedAttr &Attribute, | 
|  | MissingAttributeSubjectRulesRecoveryPoint Point, Parser &PRef) { | 
|  | SourceLocation Loc = PRef.getEndOfPreviousToken(); | 
|  | if (Loc.isInvalid()) | 
|  | Loc = PRef.getCurToken().getLocation(); | 
|  | auto Diagnostic = PRef.Diag(Loc, DiagID); | 
|  | std::string FixIt; | 
|  | MissingAttributeSubjectRulesRecoveryPoint EndPoint = | 
|  | getAttributeSubjectRulesRecoveryPointForToken(PRef.getCurToken()); | 
|  | if (Point == MissingAttributeSubjectRulesRecoveryPoint::Comma) | 
|  | FixIt = ", "; | 
|  | if (Point <= MissingAttributeSubjectRulesRecoveryPoint::ApplyTo && | 
|  | EndPoint > MissingAttributeSubjectRulesRecoveryPoint::ApplyTo) | 
|  | FixIt += "apply_to"; | 
|  | if (Point <= MissingAttributeSubjectRulesRecoveryPoint::Equals && | 
|  | EndPoint > MissingAttributeSubjectRulesRecoveryPoint::Equals) | 
|  | FixIt += " = "; | 
|  | SourceRange FixItRange(Loc); | 
|  | if (EndPoint == MissingAttributeSubjectRulesRecoveryPoint::None) { | 
|  | // Gather the subject match rules that are supported by the attribute. | 
|  | SmallVector<std::pair<attr::SubjectMatchRule, bool>, 4> SubjectMatchRuleSet; | 
|  | Attribute.getMatchRules(PRef.getLangOpts(), SubjectMatchRuleSet); | 
|  | if (SubjectMatchRuleSet.empty()) { | 
|  | // FIXME: We can emit a "fix-it" with a subject list placeholder when | 
|  | // placeholders will be supported by the fix-its. | 
|  | return Diagnostic; | 
|  | } | 
|  | FixIt += "any("; | 
|  | bool NeedsComma = false; | 
|  | for (const auto &I : SubjectMatchRuleSet) { | 
|  | // Ensure that the missing rule is reported in the fix-it only when it's | 
|  | // supported in the current language mode. | 
|  | if (!I.second) | 
|  | continue; | 
|  | if (NeedsComma) | 
|  | FixIt += ", "; | 
|  | else | 
|  | NeedsComma = true; | 
|  | FixIt += attr::getSubjectMatchRuleSpelling(I.first); | 
|  | } | 
|  | FixIt += ")"; | 
|  | // Check if we need to remove the range | 
|  | PRef.SkipUntil(tok::eof, Parser::StopBeforeMatch); | 
|  | FixItRange.setEnd(PRef.getCurToken().getLocation()); | 
|  | } | 
|  | if (FixItRange.getBegin() == FixItRange.getEnd()) | 
|  | Diagnostic << FixItHint::CreateInsertion(FixItRange.getBegin(), FixIt); | 
|  | else | 
|  | Diagnostic << FixItHint::CreateReplacement( | 
|  | CharSourceRange::getCharRange(FixItRange), FixIt); | 
|  | return Diagnostic; | 
|  | } | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  | void Parser::HandlePragmaAttribute() { | 
|  | assert(Tok.is(tok::annot_pragma_attribute) && | 
|  | "Expected #pragma attribute annotation token"); | 
|  | SourceLocation PragmaLoc = Tok.getLocation(); | 
|  | auto *Info = static_cast<PragmaAttributeInfo *>(Tok.getAnnotationValue()); | 
|  | if (Info->Action == PragmaAttributeInfo::Pop) { | 
|  | ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaAttributePop(PragmaLoc, Info->Namespace); | 
|  | return; | 
|  | } | 
|  | // Parse the actual attribute with its arguments. | 
|  | assert((Info->Action == PragmaAttributeInfo::Push || | 
|  | Info->Action == PragmaAttributeInfo::Attribute) && | 
|  | "Unexpected #pragma attribute command"); | 
|  |  | 
|  | if (Info->Action == PragmaAttributeInfo::Push && Info->Tokens.empty()) { | 
|  | ConsumeAnnotationToken(); | 
|  | Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc, Info->Namespace); | 
|  | return; | 
|  | } | 
|  |  | 
|  | PP.EnterTokenStream(Info->Tokens, /*DisableMacroExpansion=*/false, | 
|  | /*IsReinject=*/false); | 
|  | ConsumeAnnotationToken(); | 
|  |  | 
|  | ParsedAttributes &Attrs = Info->Attributes; | 
|  | Attrs.clearListOnly(); | 
|  |  | 
|  | auto SkipToEnd = [this]() { | 
|  | SkipUntil(tok::eof, StopBeforeMatch); | 
|  | ConsumeToken(); | 
|  | }; | 
|  |  | 
|  | if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { | 
|  | // Parse the CXX11 style attribute. | 
|  | ParseCXX11AttributeSpecifier(Attrs); | 
|  | } else if (Tok.is(tok::kw___attribute)) { | 
|  | ConsumeToken(); | 
|  | if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, | 
|  | "attribute")) | 
|  | return SkipToEnd(); | 
|  | if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, "(")) | 
|  | return SkipToEnd(); | 
|  |  | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | Diag(Tok, diag::err_pragma_attribute_expected_attribute_name); | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  | IdentifierInfo *AttrName = Tok.getIdentifierInfo(); | 
|  | SourceLocation AttrNameLoc = ConsumeToken(); | 
|  |  | 
|  | if (Tok.isNot(tok::l_paren)) | 
|  | Attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, | 
|  | ParsedAttr::AS_GNU); | 
|  | else | 
|  | ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, /*EndLoc=*/nullptr, | 
|  | /*ScopeName=*/nullptr, | 
|  | /*ScopeLoc=*/SourceLocation(), ParsedAttr::AS_GNU, | 
|  | /*Declarator=*/nullptr); | 
|  |  | 
|  | if (ExpectAndConsume(tok::r_paren)) | 
|  | return SkipToEnd(); | 
|  | if (ExpectAndConsume(tok::r_paren)) | 
|  | return SkipToEnd(); | 
|  | } else if (Tok.is(tok::kw___declspec)) { | 
|  | ParseMicrosoftDeclSpecs(Attrs); | 
|  | } else { | 
|  | Diag(Tok, diag::err_pragma_attribute_expected_attribute_syntax); | 
|  | if (Tok.getIdentifierInfo()) { | 
|  | // If we suspect that this is an attribute suggest the use of | 
|  | // '__attribute__'. | 
|  | if (ParsedAttr::getParsedKind( | 
|  | Tok.getIdentifierInfo(), /*ScopeName=*/nullptr, | 
|  | ParsedAttr::AS_GNU) != ParsedAttr::UnknownAttribute) { | 
|  | SourceLocation InsertStartLoc = Tok.getLocation(); | 
|  | ConsumeToken(); | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | ConsumeAnyToken(); | 
|  | SkipUntil(tok::r_paren, StopBeforeMatch); | 
|  | if (Tok.isNot(tok::r_paren)) | 
|  | return SkipToEnd(); | 
|  | } | 
|  | Diag(Tok, diag::note_pragma_attribute_use_attribute_kw) | 
|  | << FixItHint::CreateInsertion(InsertStartLoc, "__attribute__((") | 
|  | << FixItHint::CreateInsertion(Tok.getEndLoc(), "))"); | 
|  | } | 
|  | } | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Attrs.empty() || Attrs.begin()->isInvalid()) { | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Ensure that we don't have more than one attribute. | 
|  | if (Attrs.size() > 1) { | 
|  | SourceLocation Loc = Attrs[1].getLoc(); | 
|  | Diag(Loc, diag::err_pragma_attribute_multiple_attributes); | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | ParsedAttr &Attribute = *Attrs.begin(); | 
|  | if (!Attribute.isSupportedByPragmaAttribute()) { | 
|  | Diag(PragmaLoc, diag::err_pragma_attribute_unsupported_attribute) | 
|  | << Attribute; | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Parse the subject-list. | 
|  | if (!TryConsumeToken(tok::comma)) { | 
|  | createExpectedAttributeSubjectRulesTokenDiagnostic( | 
|  | diag::err_expected, Attribute, | 
|  | MissingAttributeSubjectRulesRecoveryPoint::Comma, *this) | 
|  | << tok::comma; | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | createExpectedAttributeSubjectRulesTokenDiagnostic( | 
|  | diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute, | 
|  | MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this); | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (!II->isStr("apply_to")) { | 
|  | createExpectedAttributeSubjectRulesTokenDiagnostic( | 
|  | diag::err_pragma_attribute_invalid_subject_set_specifier, Attribute, | 
|  | MissingAttributeSubjectRulesRecoveryPoint::ApplyTo, *this); | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  | ConsumeToken(); | 
|  |  | 
|  | if (!TryConsumeToken(tok::equal)) { | 
|  | createExpectedAttributeSubjectRulesTokenDiagnostic( | 
|  | diag::err_expected, Attribute, | 
|  | MissingAttributeSubjectRulesRecoveryPoint::Equals, *this) | 
|  | << tok::equal; | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | attr::ParsedSubjectMatchRuleSet SubjectMatchRules; | 
|  | SourceLocation AnyLoc, LastMatchRuleEndLoc; | 
|  | if (ParsePragmaAttributeSubjectMatchRuleSet(SubjectMatchRules, AnyLoc, | 
|  | LastMatchRuleEndLoc)) { | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Tokens following an ill-formed attribute will remain in the token stream | 
|  | // and must be removed. | 
|  | if (Tok.isNot(tok::eof)) { | 
|  | Diag(Tok, diag::err_pragma_attribute_extra_tokens_after_attribute); | 
|  | SkipToEnd(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Consume the eof terminator token. | 
|  | ConsumeToken(); | 
|  |  | 
|  | // Handle a mixed push/attribute by desurging to a push, then an attribute. | 
|  | if (Info->Action == PragmaAttributeInfo::Push) | 
|  | Actions.ActOnPragmaAttributeEmptyPush(PragmaLoc, Info->Namespace); | 
|  |  | 
|  | Actions.ActOnPragmaAttributeAttribute(Attribute, PragmaLoc, | 
|  | std::move(SubjectMatchRules)); | 
|  | } | 
|  |  | 
|  | // #pragma GCC visibility comes in two variants: | 
|  | //   'push' '(' [visibility] ')' | 
|  | //   'pop' | 
|  | void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &VisTok) { | 
|  | SourceLocation VisLoc = VisTok.getLocation(); | 
|  |  | 
|  | Token Tok; | 
|  | PP.LexUnexpandedToken(Tok); | 
|  |  | 
|  | const IdentifierInfo *PushPop = Tok.getIdentifierInfo(); | 
|  |  | 
|  | const IdentifierInfo *VisType; | 
|  | if (PushPop && PushPop->isStr("pop")) { | 
|  | VisType = nullptr; | 
|  | } else if (PushPop && PushPop->isStr("push")) { | 
|  | PP.LexUnexpandedToken(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) | 
|  | << "visibility"; | 
|  | return; | 
|  | } | 
|  | PP.LexUnexpandedToken(Tok); | 
|  | VisType = Tok.getIdentifierInfo(); | 
|  | if (!VisType) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | 
|  | << "visibility"; | 
|  | return; | 
|  | } | 
|  | PP.LexUnexpandedToken(Tok); | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) | 
|  | << "visibility"; | 
|  | return; | 
|  | } | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | 
|  | << "visibility"; | 
|  | return; | 
|  | } | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | PP.LexUnexpandedToken(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "visibility"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | auto Toks = std::make_unique<Token[]>(1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_vis); | 
|  | Toks[0].setLocation(VisLoc); | 
|  | Toks[0].setAnnotationEndLoc(EndLoc); | 
|  | Toks[0].setAnnotationValue( | 
|  | const_cast<void *>(static_cast<const void *>(VisType))); | 
|  | PP.EnterTokenStream(std::move(Toks), 1, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | // #pragma pack(...) comes in the following delicious flavors: | 
|  | //   pack '(' [integer] ')' | 
|  | //   pack '(' 'show' ')' | 
|  | //   pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' | 
|  | void PragmaPackHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &PackTok) { | 
|  | SourceLocation PackLoc = PackTok.getLocation(); | 
|  |  | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "pack"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | Sema::PragmaMsStackAction Action = Sema::PSK_Reset; | 
|  | StringRef SlotLabel; | 
|  | Token Alignment; | 
|  | Alignment.startToken(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::numeric_constant)) { | 
|  | Alignment = Tok; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | // In MSVC/gcc, #pragma pack(4) sets the alignment without affecting | 
|  | // the push/pop stack. | 
|  | // In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4) | 
|  | Action = | 
|  | PP.getLangOpts().ApplePragmaPack ? Sema::PSK_Push_Set : Sema::PSK_Set; | 
|  | } else if (Tok.is(tok::identifier)) { | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (II->isStr("show")) { | 
|  | Action = Sema::PSK_Show; | 
|  | PP.Lex(Tok); | 
|  | } else { | 
|  | if (II->isStr("push")) { | 
|  | Action = Sema::PSK_Push; | 
|  | } else if (II->isStr("pop")) { | 
|  | Action = Sema::PSK_Pop; | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) << "pack"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.is(tok::comma)) { | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.is(tok::numeric_constant)) { | 
|  | Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); | 
|  | Alignment = Tok; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | } else if (Tok.is(tok::identifier)) { | 
|  | SlotLabel = Tok.getIdentifierInfo()->getName(); | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.is(tok::comma)) { | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::numeric_constant)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); | 
|  | Alignment = Tok; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | } | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_malformed); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  | } else if (PP.getLangOpts().ApplePragmaPack) { | 
|  | // In MSVC/gcc, #pragma pack() resets the alignment without affecting | 
|  | // the push/pop stack. | 
|  | // In Apple gcc #pragma pack() is equivalent to #pragma pack(pop). | 
|  | Action = Sema::PSK_Pop; | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "pack"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourceLocation RParenLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "pack"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PragmaPackInfo *Info = | 
|  | PP.getPreprocessorAllocator().Allocate<PragmaPackInfo>(1); | 
|  | Info->Action = Action; | 
|  | Info->SlotLabel = SlotLabel; | 
|  | Info->Alignment = Alignment; | 
|  |  | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | 
|  | 1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_pack); | 
|  | Toks[0].setLocation(PackLoc); | 
|  | Toks[0].setAnnotationEndLoc(RParenLoc); | 
|  | Toks[0].setAnnotationValue(static_cast<void*>(Info)); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | // #pragma ms_struct on | 
|  | // #pragma ms_struct off | 
|  | void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &MSStructTok) { | 
|  | PragmaMSStructKind Kind = PMSST_OFF; | 
|  |  | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); | 
|  | return; | 
|  | } | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (II->isStr("on")) { | 
|  | Kind = PMSST_ON; | 
|  | PP.Lex(Tok); | 
|  | } | 
|  | else if (II->isStr("off") || II->isStr("reset")) | 
|  | PP.Lex(Tok); | 
|  | else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "ms_struct"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | 
|  | 1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_msstruct); | 
|  | Toks[0].setLocation(MSStructTok.getLocation()); | 
|  | Toks[0].setAnnotationEndLoc(EndLoc); | 
|  | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | 
|  | static_cast<uintptr_t>(Kind))); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | // #pragma clang section bss="abc" data="" rodata="def" text="" relro="" | 
|  | void PragmaClangSectionHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &FirstToken) { | 
|  |  | 
|  | Token Tok; | 
|  | auto SecKind = Sema::PragmaClangSectionKind::PCSK_Invalid; | 
|  |  | 
|  | PP.Lex(Tok); // eat 'section' | 
|  | while (Tok.isNot(tok::eod)) { | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | const IdentifierInfo *SecType = Tok.getIdentifierInfo(); | 
|  | if (SecType->isStr("bss")) | 
|  | SecKind = Sema::PragmaClangSectionKind::PCSK_BSS; | 
|  | else if (SecType->isStr("data")) | 
|  | SecKind = Sema::PragmaClangSectionKind::PCSK_Data; | 
|  | else if (SecType->isStr("rodata")) | 
|  | SecKind = Sema::PragmaClangSectionKind::PCSK_Rodata; | 
|  | else if (SecType->isStr("relro")) | 
|  | SecKind = Sema::PragmaClangSectionKind::PCSK_Relro; | 
|  | else if (SecType->isStr("text")) | 
|  | SecKind = Sema::PragmaClangSectionKind::PCSK_Text; | 
|  | else { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_clang_section_name) << "clang section"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourceLocation PragmaLocation = Tok.getLocation(); | 
|  | PP.Lex(Tok); // eat ['bss'|'data'|'rodata'|'text'] | 
|  | if (Tok.isNot(tok::equal)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_clang_section_expected_equal) << SecKind; | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::string SecName; | 
|  | if (!PP.LexStringLiteral(Tok, SecName, "pragma clang section", false)) | 
|  | return; | 
|  |  | 
|  | Actions.ActOnPragmaClangSection( | 
|  | PragmaLocation, | 
|  | (SecName.size() ? Sema::PragmaClangSectionAction::PCSA_Set | 
|  | : Sema::PragmaClangSectionAction::PCSA_Clear), | 
|  | SecKind, SecName); | 
|  | } | 
|  | } | 
|  |  | 
|  | // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} | 
|  | // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} | 
|  | static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, | 
|  | bool IsOptions) { | 
|  | Token Tok; | 
|  |  | 
|  | if (IsOptions) { | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier) || | 
|  | !Tok.getIdentifierInfo()->isStr("align")) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_options_expected_align); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::equal)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_align_expected_equal) | 
|  | << IsOptions; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | 
|  | << (IsOptions ? "options" : "align"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Sema::PragmaOptionsAlignKind Kind = Sema::POAK_Natural; | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (II->isStr("native")) | 
|  | Kind = Sema::POAK_Native; | 
|  | else if (II->isStr("natural")) | 
|  | Kind = Sema::POAK_Natural; | 
|  | else if (II->isStr("packed")) | 
|  | Kind = Sema::POAK_Packed; | 
|  | else if (II->isStr("power")) | 
|  | Kind = Sema::POAK_Power; | 
|  | else if (II->isStr("mac68k")) | 
|  | Kind = Sema::POAK_Mac68k; | 
|  | else if (II->isStr("reset")) | 
|  | Kind = Sema::POAK_Reset; | 
|  | else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_align_invalid_option) | 
|  | << IsOptions; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << (IsOptions ? "options" : "align"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | 
|  | 1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_align); | 
|  | Toks[0].setLocation(FirstTok.getLocation()); | 
|  | Toks[0].setAnnotationEndLoc(EndLoc); | 
|  | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | 
|  | static_cast<uintptr_t>(Kind))); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | void PragmaAlignHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &AlignTok) { | 
|  | ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false); | 
|  | } | 
|  |  | 
|  | void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &OptionsTok) { | 
|  | ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true); | 
|  | } | 
|  |  | 
|  | // #pragma unused(identifier) | 
|  | void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &UnusedTok) { | 
|  | // FIXME: Should we be expanding macros here? My guess is no. | 
|  | SourceLocation UnusedLoc = UnusedTok.getLocation(); | 
|  |  | 
|  | // Lex the left '('. | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "unused"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Lex the declaration reference(s). | 
|  | SmallVector<Token, 5> Identifiers; | 
|  | SourceLocation RParenLoc; | 
|  | bool LexID = true; | 
|  |  | 
|  | while (true) { | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (LexID) { | 
|  | if (Tok.is(tok::identifier)) { | 
|  | Identifiers.push_back(Tok); | 
|  | LexID = false; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Illegal token! | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_var); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // We are execting a ')' or a ','. | 
|  | if (Tok.is(tok::comma)) { | 
|  | LexID = true; | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (Tok.is(tok::r_paren)) { | 
|  | RParenLoc = Tok.getLocation(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Illegal token! | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_punc) << "unused"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << | 
|  | "unused"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Verify that we have a location for the right parenthesis. | 
|  | assert(RParenLoc.isValid() && "Valid '#pragma unused' must have ')'"); | 
|  | assert(!Identifiers.empty() && "Valid '#pragma unused' must have arguments"); | 
|  |  | 
|  | // For each identifier token, insert into the token stream a | 
|  | // annot_pragma_unused token followed by the identifier token. | 
|  | // This allows us to cache a "#pragma unused" that occurs inside an inline | 
|  | // C++ member function. | 
|  |  | 
|  | MutableArrayRef<Token> Toks( | 
|  | PP.getPreprocessorAllocator().Allocate<Token>(2 * Identifiers.size()), | 
|  | 2 * Identifiers.size()); | 
|  | for (unsigned i=0; i != Identifiers.size(); i++) { | 
|  | Token &pragmaUnusedTok = Toks[2*i], &idTok = Toks[2*i+1]; | 
|  | pragmaUnusedTok.startToken(); | 
|  | pragmaUnusedTok.setKind(tok::annot_pragma_unused); | 
|  | pragmaUnusedTok.setLocation(UnusedLoc); | 
|  | idTok = Identifiers[i]; | 
|  | } | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | // #pragma weak identifier | 
|  | // #pragma weak identifier '=' identifier | 
|  | void PragmaWeakHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &WeakTok) { | 
|  | SourceLocation WeakLoc = WeakTok.getLocation(); | 
|  |  | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | Token WeakName = Tok; | 
|  | bool HasAlias = false; | 
|  | Token AliasName; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::equal)) { | 
|  | HasAlias = true; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | 
|  | << "weak"; | 
|  | return; | 
|  | } | 
|  | AliasName = Tok; | 
|  | PP.Lex(Tok); | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << "weak"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (HasAlias) { | 
|  | MutableArrayRef<Token> Toks( | 
|  | PP.getPreprocessorAllocator().Allocate<Token>(3), 3); | 
|  | Token &pragmaUnusedTok = Toks[0]; | 
|  | pragmaUnusedTok.startToken(); | 
|  | pragmaUnusedTok.setKind(tok::annot_pragma_weakalias); | 
|  | pragmaUnusedTok.setLocation(WeakLoc); | 
|  | pragmaUnusedTok.setAnnotationEndLoc(AliasName.getLocation()); | 
|  | Toks[1] = WeakName; | 
|  | Toks[2] = AliasName; | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } else { | 
|  | MutableArrayRef<Token> Toks( | 
|  | PP.getPreprocessorAllocator().Allocate<Token>(2), 2); | 
|  | Token &pragmaUnusedTok = Toks[0]; | 
|  | pragmaUnusedTok.startToken(); | 
|  | pragmaUnusedTok.setKind(tok::annot_pragma_weak); | 
|  | pragmaUnusedTok.setLocation(WeakLoc); | 
|  | pragmaUnusedTok.setAnnotationEndLoc(WeakLoc); | 
|  | Toks[1] = WeakName; | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  | } | 
|  |  | 
|  | // #pragma redefine_extname identifier identifier | 
|  | void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &RedefToken) { | 
|  | SourceLocation RedefLoc = RedefToken.getLocation(); | 
|  |  | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << | 
|  | "redefine_extname"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | Token RedefName = Tok; | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | 
|  | << "redefine_extname"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | Token AliasName = Tok; | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << | 
|  | "redefine_extname"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(3), | 
|  | 3); | 
|  | Token &pragmaRedefTok = Toks[0]; | 
|  | pragmaRedefTok.startToken(); | 
|  | pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname); | 
|  | pragmaRedefTok.setLocation(RedefLoc); | 
|  | pragmaRedefTok.setAnnotationEndLoc(AliasName.getLocation()); | 
|  | Toks[1] = RedefName; | 
|  | Toks[2] = AliasName; | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | void PragmaFPContractHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | tok::OnOffSwitch OOS; | 
|  | if (PP.LexOnOffSwitch(OOS)) | 
|  | return; | 
|  |  | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | 
|  | 1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_fp_contract); | 
|  | Toks[0].setLocation(Tok.getLocation()); | 
|  | Toks[0].setAnnotationEndLoc(Tok.getLocation()); | 
|  | Toks[0].setAnnotationValue(reinterpret_cast<void*>( | 
|  | static_cast<uintptr_t>(OOS))); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | void PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | PP.LexUnexpandedToken(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << | 
|  | "OPENCL"; | 
|  | return; | 
|  | } | 
|  | IdentifierInfo *Ext = Tok.getIdentifierInfo(); | 
|  | SourceLocation NameLoc = Tok.getLocation(); | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::colon)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << Ext; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_predicate) << 0; | 
|  | return; | 
|  | } | 
|  | IdentifierInfo *Pred = Tok.getIdentifierInfo(); | 
|  |  | 
|  | OpenCLExtState State; | 
|  | if (Pred->isStr("enable")) { | 
|  | State = Enable; | 
|  | } else if (Pred->isStr("disable")) { | 
|  | State = Disable; | 
|  | } else if (Pred->isStr("begin")) | 
|  | State = Begin; | 
|  | else if (Pred->isStr("end")) | 
|  | State = End; | 
|  | else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_predicate) | 
|  | << Ext->isStr("all"); | 
|  | return; | 
|  | } | 
|  | SourceLocation StateLoc = Tok.getLocation(); | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << | 
|  | "OPENCL EXTENSION"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | auto Info = PP.getPreprocessorAllocator().Allocate<OpenCLExtData>(1); | 
|  | Info->first = Ext; | 
|  | Info->second = State; | 
|  | MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1), | 
|  | 1); | 
|  | Toks[0].startToken(); | 
|  | Toks[0].setKind(tok::annot_pragma_opencl_extension); | 
|  | Toks[0].setLocation(NameLoc); | 
|  | Toks[0].setAnnotationValue(static_cast<void*>(Info)); | 
|  | Toks[0].setAnnotationEndLoc(StateLoc); | 
|  | PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true, | 
|  | /*IsReinject=*/false); | 
|  |  | 
|  | if (PP.getPPCallbacks()) | 
|  | PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, Ext, | 
|  | StateLoc, State); | 
|  | } | 
|  |  | 
|  | /// Handle '#pragma omp ...' when OpenMP is disabled. | 
|  | /// | 
|  | void PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &FirstTok) { | 
|  | if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored, | 
|  | FirstTok.getLocation())) { | 
|  | PP.Diag(FirstTok, diag::warn_pragma_omp_ignored); | 
|  | PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored, | 
|  | diag::Severity::Ignored, SourceLocation()); | 
|  | } | 
|  | PP.DiscardUntilEndOfDirective(); | 
|  | } | 
|  |  | 
|  | /// Handle '#pragma omp ...' when OpenMP is enabled. | 
|  | /// | 
|  | void PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &FirstTok) { | 
|  | SmallVector<Token, 16> Pragma; | 
|  | Token Tok; | 
|  | Tok.startToken(); | 
|  | Tok.setKind(tok::annot_pragma_openmp); | 
|  | Tok.setLocation(Introducer.Loc); | 
|  |  | 
|  | while (Tok.isNot(tok::eod) && Tok.isNot(tok::eof)) { | 
|  | Pragma.push_back(Tok); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::annot_pragma_openmp)) { | 
|  | PP.Diag(Tok, diag::err_omp_unexpected_directive) << 0; | 
|  | unsigned InnerPragmaCnt = 1; | 
|  | while (InnerPragmaCnt != 0) { | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::annot_pragma_openmp)) | 
|  | ++InnerPragmaCnt; | 
|  | else if (Tok.is(tok::annot_pragma_openmp_end)) | 
|  | --InnerPragmaCnt; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  | } | 
|  | } | 
|  | SourceLocation EodLoc = Tok.getLocation(); | 
|  | Tok.startToken(); | 
|  | Tok.setKind(tok::annot_pragma_openmp_end); | 
|  | Tok.setLocation(EodLoc); | 
|  | Pragma.push_back(Tok); | 
|  |  | 
|  | auto Toks = std::make_unique<Token[]>(Pragma.size()); | 
|  | std::copy(Pragma.begin(), Pragma.end(), Toks.get()); | 
|  | PP.EnterTokenStream(std::move(Toks), Pragma.size(), | 
|  | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | /// Handle '#pragma pointers_to_members' | 
|  | // The grammar for this pragma is as follows: | 
|  | // | 
|  | // <inheritance model> ::= ('single' | 'multiple' | 'virtual') '_inheritance' | 
|  | // | 
|  | // #pragma pointers_to_members '(' 'best_case' ')' | 
|  | // #pragma pointers_to_members '(' 'full_generality' [',' inheritance-model] ')' | 
|  | // #pragma pointers_to_members '(' inheritance-model ')' | 
|  | void PragmaMSPointersToMembers::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | SourceLocation PointersToMembersLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(PointersToMembersLoc, diag::warn_pragma_expected_lparen) | 
|  | << "pointers_to_members"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  | const IdentifierInfo *Arg = Tok.getIdentifierInfo(); | 
|  | if (!Arg) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) | 
|  | << "pointers_to_members"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | LangOptions::PragmaMSPointersToMembersKind RepresentationMethod; | 
|  | if (Arg->isStr("best_case")) { | 
|  | RepresentationMethod = LangOptions::PPTMK_BestCase; | 
|  | } else { | 
|  | if (Arg->isStr("full_generality")) { | 
|  | if (Tok.is(tok::comma)) { | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | Arg = Tok.getIdentifierInfo(); | 
|  | if (!Arg) { | 
|  | PP.Diag(Tok.getLocation(), | 
|  | diag::err_pragma_pointers_to_members_unknown_kind) | 
|  | << Tok.getKind() << /*OnlyInheritanceModels*/ 0; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  | } else if (Tok.is(tok::r_paren)) { | 
|  | // #pragma pointers_to_members(full_generality) implicitly specifies | 
|  | // virtual_inheritance. | 
|  | Arg = nullptr; | 
|  | RepresentationMethod = LangOptions::PPTMK_FullGeneralityVirtualInheritance; | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected_punc) | 
|  | << "full_generality"; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Arg) { | 
|  | if (Arg->isStr("single_inheritance")) { | 
|  | RepresentationMethod = | 
|  | LangOptions::PPTMK_FullGeneralitySingleInheritance; | 
|  | } else if (Arg->isStr("multiple_inheritance")) { | 
|  | RepresentationMethod = | 
|  | LangOptions::PPTMK_FullGeneralityMultipleInheritance; | 
|  | } else if (Arg->isStr("virtual_inheritance")) { | 
|  | RepresentationMethod = | 
|  | LangOptions::PPTMK_FullGeneralityVirtualInheritance; | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), | 
|  | diag::err_pragma_pointers_to_members_unknown_kind) | 
|  | << Arg << /*HasPointerDeclaration*/ 1; | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected_rparen_after) | 
|  | << (Arg ? Arg->getName() : "full_generality"); | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "pointers_to_members"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | Token AnnotTok; | 
|  | AnnotTok.startToken(); | 
|  | AnnotTok.setKind(tok::annot_pragma_ms_pointers_to_members); | 
|  | AnnotTok.setLocation(PointersToMembersLoc); | 
|  | AnnotTok.setAnnotationEndLoc(EndLoc); | 
|  | AnnotTok.setAnnotationValue( | 
|  | reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod))); | 
|  | PP.EnterToken(AnnotTok, /*IsReinject=*/true); | 
|  | } | 
|  |  | 
|  | /// Handle '#pragma vtordisp' | 
|  | // The grammar for this pragma is as follows: | 
|  | // | 
|  | // <vtordisp-mode> ::= ('off' | 'on' | '0' | '1' | '2' ) | 
|  | // | 
|  | // #pragma vtordisp '(' ['push' ','] vtordisp-mode ')' | 
|  | // #pragma vtordisp '(' 'pop' ')' | 
|  | // #pragma vtordisp '(' ')' | 
|  | void PragmaMSVtorDisp::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, Token &Tok) { | 
|  | SourceLocation VtorDispLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(VtorDispLoc, diag::warn_pragma_expected_lparen) << "vtordisp"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | Sema::PragmaMsStackAction Action = Sema::PSK_Set; | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (II) { | 
|  | if (II->isStr("push")) { | 
|  | // #pragma vtordisp(push, mode) | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::comma)) { | 
|  | PP.Diag(VtorDispLoc, diag::warn_pragma_expected_punc) << "vtordisp"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  | Action = Sema::PSK_Push_Set; | 
|  | // not push, could be on/off | 
|  | } else if (II->isStr("pop")) { | 
|  | // #pragma vtordisp(pop) | 
|  | PP.Lex(Tok); | 
|  | Action = Sema::PSK_Pop; | 
|  | } | 
|  | // not push or pop, could be on/off | 
|  | } else { | 
|  | if (Tok.is(tok::r_paren)) { | 
|  | // #pragma vtordisp() | 
|  | Action = Sema::PSK_Reset; | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | uint64_t Value = 0; | 
|  | if (Action & Sema::PSK_Push || Action & Sema::PSK_Set) { | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (II && II->isStr("off")) { | 
|  | PP.Lex(Tok); | 
|  | Value = 0; | 
|  | } else if (II && II->isStr("on")) { | 
|  | PP.Lex(Tok); | 
|  | Value = 1; | 
|  | } else if (Tok.is(tok::numeric_constant) && | 
|  | PP.parseSimpleIntegerLiteral(Tok, Value)) { | 
|  | if (Value > 2) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_integer) | 
|  | << 0 << 2 << "vtordisp"; | 
|  | return; | 
|  | } | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) | 
|  | << "vtordisp"; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Finish the pragma: ')' $ | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(VtorDispLoc, diag::warn_pragma_expected_rparen) << "vtordisp"; | 
|  | return; | 
|  | } | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "vtordisp"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Enter the annotation. | 
|  | Token AnnotTok; | 
|  | AnnotTok.startToken(); | 
|  | AnnotTok.setKind(tok::annot_pragma_ms_vtordisp); | 
|  | AnnotTok.setLocation(VtorDispLoc); | 
|  | AnnotTok.setAnnotationEndLoc(EndLoc); | 
|  | AnnotTok.setAnnotationValue(reinterpret_cast<void *>( | 
|  | static_cast<uintptr_t>((Action << 16) | (Value & 0xFFFF)))); | 
|  | PP.EnterToken(AnnotTok, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | /// Handle all MS pragmas.  Simply forwards the tokens after inserting | 
|  | /// an annotation token. | 
|  | void PragmaMSPragma::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, Token &Tok) { | 
|  | Token EoF, AnnotTok; | 
|  | EoF.startToken(); | 
|  | EoF.setKind(tok::eof); | 
|  | AnnotTok.startToken(); | 
|  | AnnotTok.setKind(tok::annot_pragma_ms_pragma); | 
|  | AnnotTok.setLocation(Tok.getLocation()); | 
|  | AnnotTok.setAnnotationEndLoc(Tok.getLocation()); | 
|  | SmallVector<Token, 8> TokenVector; | 
|  | // Suck up all of the tokens before the eod. | 
|  | for (; Tok.isNot(tok::eod); PP.Lex(Tok)) { | 
|  | TokenVector.push_back(Tok); | 
|  | AnnotTok.setAnnotationEndLoc(Tok.getLocation()); | 
|  | } | 
|  | // Add a sentinel EoF token to the end of the list. | 
|  | TokenVector.push_back(EoF); | 
|  | // We must allocate this array with new because EnterTokenStream is going to | 
|  | // delete it later. | 
|  | auto TokenArray = std::make_unique<Token[]>(TokenVector.size()); | 
|  | std::copy(TokenVector.begin(), TokenVector.end(), TokenArray.get()); | 
|  | auto Value = new (PP.getPreprocessorAllocator()) | 
|  | std::pair<std::unique_ptr<Token[]>, size_t>(std::move(TokenArray), | 
|  | TokenVector.size()); | 
|  | AnnotTok.setAnnotationValue(Value); | 
|  | PP.EnterToken(AnnotTok, /*IsReinject*/ false); | 
|  | } | 
|  |  | 
|  | /// Handle the \#pragma float_control extension. | 
|  | /// | 
|  | /// The syntax is: | 
|  | /// \code | 
|  | ///   #pragma float_control(keyword[, setting] [,push]) | 
|  | /// \endcode | 
|  | /// Where 'keyword' and 'setting' are identifiers. | 
|  | // 'keyword' can be: precise, except, push, pop | 
|  | // 'setting' can be: on, off | 
|  | /// The optional arguments 'setting' and 'push' are supported only | 
|  | /// when the keyword is 'precise' or 'except'. | 
|  | void PragmaFloatControlHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | Sema::PragmaMsStackAction Action = Sema::PSK_Set; | 
|  | SourceLocation FloatControlLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(FloatControlLoc, diag::err_expected) << tok::l_paren; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Read the identifier. | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Verify that this is one of the float control options. | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | PragmaFloatControlKind Kind = | 
|  | llvm::StringSwitch<PragmaFloatControlKind>(II->getName()) | 
|  | .Case("precise", PFC_Precise) | 
|  | .Case("except", PFC_Except) | 
|  | .Case("push", PFC_Push) | 
|  | .Case("pop", PFC_Pop) | 
|  | .Default(PFC_Unknown); | 
|  | PP.Lex(Tok); // the identifier | 
|  | if (Kind == PFC_Unknown) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } else if (Kind == PFC_Push || Kind == PFC_Pop) { | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); // Eat the r_paren | 
|  | Action = (Kind == PFC_Pop) ? Sema::PSK_Pop : Sema::PSK_Push; | 
|  | } else { | 
|  | if (Tok.is(tok::r_paren)) | 
|  | // Selecting Precise or Except | 
|  | PP.Lex(Tok); // the r_paren | 
|  | else if (Tok.isNot(tok::comma)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } else { | 
|  | PP.Lex(Tok); // , | 
|  | if (!Tok.isAnyIdentifier()) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  | StringRef PushOnOff = Tok.getIdentifierInfo()->getName(); | 
|  | if (PushOnOff == "on") | 
|  | // Kind is set correctly | 
|  | ; | 
|  | else if (PushOnOff == "off") { | 
|  | if (Kind == PFC_Precise) | 
|  | Kind = PFC_NoPrecise; | 
|  | if (Kind == PFC_Except) | 
|  | Kind = PFC_NoExcept; | 
|  | } else if (PushOnOff == "push") { | 
|  | Action = Sema::PSK_Push_Set; | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); // the identifier | 
|  | if (Tok.is(tok::comma)) { | 
|  | PP.Lex(Tok); // , | 
|  | if (!Tok.isAnyIdentifier()) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  | StringRef ExpectedPush = Tok.getIdentifierInfo()->getName(); | 
|  | if (ExpectedPush == "push") { | 
|  | Action = Sema::PSK_Push_Set; | 
|  | } else { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); // the push identifier | 
|  | } | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_float_control_malformed); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); // the r_paren | 
|  | } | 
|  | } | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "float_control"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Note: there is no accomodation for PP callback for this pragma. | 
|  |  | 
|  | // Enter the annotation. | 
|  | auto TokenArray = std::make_unique<Token[]>(1); | 
|  | TokenArray[0].startToken(); | 
|  | TokenArray[0].setKind(tok::annot_pragma_float_control); | 
|  | TokenArray[0].setLocation(FloatControlLoc); | 
|  | TokenArray[0].setAnnotationEndLoc(EndLoc); | 
|  | // Create an encoding of Action and Value by shifting the Action into | 
|  | // the high 16 bits then union with the Kind. | 
|  | TokenArray[0].setAnnotationValue(reinterpret_cast<void *>( | 
|  | static_cast<uintptr_t>((Action << 16) | (Kind & 0xFFFF)))); | 
|  | PP.EnterTokenStream(std::move(TokenArray), 1, | 
|  | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | /// Handle the Microsoft \#pragma detect_mismatch extension. | 
|  | /// | 
|  | /// The syntax is: | 
|  | /// \code | 
|  | ///   #pragma detect_mismatch("name", "value") | 
|  | /// \endcode | 
|  | /// Where 'name' and 'value' are quoted strings.  The values are embedded in | 
|  | /// the object file and passed along to the linker.  If the linker detects a | 
|  | /// mismatch in the object file's values for the given name, a LNK2038 error | 
|  | /// is emitted.  See MSDN for more details. | 
|  | void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | SourceLocation DetectMismatchLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(DetectMismatchLoc, diag::err_expected) << tok::l_paren; | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Read the name to embed, which must be a string literal. | 
|  | std::string NameString; | 
|  | if (!PP.LexStringLiteral(Tok, NameString, | 
|  | "pragma detect_mismatch", | 
|  | /*AllowMacroExpansion=*/true)) | 
|  | return; | 
|  |  | 
|  | // Read the comma followed by a second string literal. | 
|  | std::string ValueString; | 
|  | if (Tok.isNot(tok::comma)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (!PP.LexStringLiteral(Tok, ValueString, "pragma detect_mismatch", | 
|  | /*AllowMacroExpansion=*/true)) | 
|  | return; | 
|  |  | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok);  // Eat the r_paren. | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_detect_mismatch_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // If the pragma is lexically sound, notify any interested PPCallbacks. | 
|  | if (PP.getPPCallbacks()) | 
|  | PP.getPPCallbacks()->PragmaDetectMismatch(DetectMismatchLoc, NameString, | 
|  | ValueString); | 
|  |  | 
|  | Actions.ActOnPragmaDetectMismatch(DetectMismatchLoc, NameString, ValueString); | 
|  | } | 
|  |  | 
|  | /// Handle the microsoft \#pragma comment extension. | 
|  | /// | 
|  | /// The syntax is: | 
|  | /// \code | 
|  | ///   #pragma comment(linker, "foo") | 
|  | /// \endcode | 
|  | /// 'linker' is one of five identifiers: compiler, exestr, lib, linker, user. | 
|  | /// "foo" is a string, which is fully macro expanded, and permits string | 
|  | /// concatenation, embedded escape characters etc.  See MSDN for more details. | 
|  | void PragmaCommentHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | SourceLocation CommentLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Read the identifier. | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(CommentLoc, diag::err_pragma_comment_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Verify that this is one of the 5 whitelisted options. | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | PragmaMSCommentKind Kind = | 
|  | llvm::StringSwitch<PragmaMSCommentKind>(II->getName()) | 
|  | .Case("linker",   PCK_Linker) | 
|  | .Case("lib",      PCK_Lib) | 
|  | .Case("compiler", PCK_Compiler) | 
|  | .Case("exestr",   PCK_ExeStr) | 
|  | .Case("user",     PCK_User) | 
|  | .Default(PCK_Unknown); | 
|  | if (Kind == PCK_Unknown) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (PP.getTargetInfo().getTriple().isOSBinFormatELF() && Kind != PCK_Lib) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored) | 
|  | << II->getName(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // On PS4, issue a warning about any pragma comments other than | 
|  | // #pragma comment lib. | 
|  | if (PP.getTargetInfo().getTriple().isPS4() && Kind != PCK_Lib) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_comment_ignored) | 
|  | << II->getName(); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Read the optional string if present. | 
|  | PP.Lex(Tok); | 
|  | std::string ArgumentString; | 
|  | if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString, | 
|  | "pragma comment", | 
|  | /*AllowMacroExpansion=*/true)) | 
|  | return; | 
|  |  | 
|  | // FIXME: warn that 'exestr' is deprecated. | 
|  | // FIXME: If the kind is "compiler" warn if the string is present (it is | 
|  | // ignored). | 
|  | // The MSDN docs say that "lib" and "linker" require a string and have a short | 
|  | // whitelist of linker options they support, but in practice MSVC doesn't | 
|  | // issue a diagnostic.  Therefore neither does clang. | 
|  |  | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok);  // eat the r_paren. | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_comment_malformed); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // If the pragma is lexically sound, notify any interested PPCallbacks. | 
|  | if (PP.getPPCallbacks()) | 
|  | PP.getPPCallbacks()->PragmaComment(CommentLoc, II, ArgumentString); | 
|  |  | 
|  | Actions.ActOnPragmaMSComment(CommentLoc, Kind, ArgumentString); | 
|  | } | 
|  |  | 
|  | // #pragma clang optimize off | 
|  | // #pragma clang optimize on | 
|  | void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &FirstToken) { | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) | 
|  | << "clang optimize" << /*Expected=*/true << "'on' or 'off'"; | 
|  | return; | 
|  | } | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument) | 
|  | << PP.getSpelling(Tok); | 
|  | return; | 
|  | } | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | // The only accepted values are 'on' or 'off'. | 
|  | bool IsOn = false; | 
|  | if (II->isStr("on")) { | 
|  | IsOn = true; | 
|  | } else if (!II->isStr("off")) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_invalid_argument) | 
|  | << PP.getSpelling(Tok); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_optimize_extra_argument) | 
|  | << PP.getSpelling(Tok); | 
|  | return; | 
|  | } | 
|  |  | 
|  | Actions.ActOnPragmaOptimize(IsOn, FirstToken.getLocation()); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | /// Used as the annotation value for tok::annot_pragma_fp. | 
|  | struct TokFPAnnotValue { | 
|  | enum FlagKinds { Contract, Reassociate }; | 
|  | enum FlagValues { On, Off, Fast }; | 
|  |  | 
|  | FlagKinds FlagKind; | 
|  | FlagValues FlagValue; | 
|  | }; | 
|  | } // end anonymous namespace | 
|  |  | 
|  | void PragmaFPHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, Token &Tok) { | 
|  | // fp | 
|  | Token PragmaName = Tok; | 
|  | SmallVector<Token, 1> TokenList; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) | 
|  | << /*MissingOption=*/true << ""; | 
|  | return; | 
|  | } | 
|  |  | 
|  | while (Tok.is(tok::identifier)) { | 
|  | IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); | 
|  |  | 
|  | auto FlagKind = | 
|  | llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagKinds>>( | 
|  | OptionInfo->getName()) | 
|  | .Case("contract", TokFPAnnotValue::Contract) | 
|  | .Case("reassociate", TokFPAnnotValue::Reassociate) | 
|  | .Default(None); | 
|  | if (!FlagKind) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_option) | 
|  | << /*MissingOption=*/false << OptionInfo; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | // Read '(' | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | 
|  | << PP.getSpelling(Tok) << OptionInfo->getName() | 
|  | << (FlagKind == TokFPAnnotValue::Reassociate); | 
|  | return; | 
|  | } | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  |  | 
|  | auto FlagValue = | 
|  | llvm::StringSwitch<llvm::Optional<TokFPAnnotValue::FlagValues>>( | 
|  | II->getName()) | 
|  | .Case("on", TokFPAnnotValue::On) | 
|  | .Case("off", TokFPAnnotValue::Off) | 
|  | .Case("fast", TokFPAnnotValue::Fast) | 
|  | .Default(llvm::None); | 
|  |  | 
|  | if (!FlagValue || (FlagKind == TokFPAnnotValue::Reassociate && | 
|  | FlagValue == TokFPAnnotValue::Fast)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_fp_invalid_argument) | 
|  | << PP.getSpelling(Tok) << OptionInfo->getName() | 
|  | << (FlagKind == TokFPAnnotValue::Reassociate); | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | // Read ')' | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | auto *AnnotValue = new (PP.getPreprocessorAllocator()) | 
|  | TokFPAnnotValue{*FlagKind, *FlagValue}; | 
|  | // Generate the fp annotation token. | 
|  | Token FPTok; | 
|  | FPTok.startToken(); | 
|  | FPTok.setKind(tok::annot_pragma_fp); | 
|  | FPTok.setLocation(PragmaName.getLocation()); | 
|  | FPTok.setAnnotationEndLoc(PragmaName.getLocation()); | 
|  | FPTok.setAnnotationValue(reinterpret_cast<void *>(AnnotValue)); | 
|  | TokenList.push_back(FPTok); | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "clang fp"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | auto TokenArray = std::make_unique<Token[]>(TokenList.size()); | 
|  | std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); | 
|  |  | 
|  | PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), | 
|  | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | void Parser::HandlePragmaFP() { | 
|  | assert(Tok.is(tok::annot_pragma_fp)); | 
|  | auto *AnnotValue = | 
|  | reinterpret_cast<TokFPAnnotValue *>(Tok.getAnnotationValue()); | 
|  |  | 
|  | if (AnnotValue->FlagKind == TokFPAnnotValue::Reassociate) | 
|  | Actions.ActOnPragmaFPReassociate(AnnotValue->FlagValue == | 
|  | TokFPAnnotValue::On); | 
|  | else { | 
|  | LangOptions::FPModeKind FPC; | 
|  | switch (AnnotValue->FlagValue) { | 
|  | case TokFPAnnotValue::Off: | 
|  | FPC = LangOptions::FPM_Off; | 
|  | break; | 
|  | case TokFPAnnotValue::On: | 
|  | FPC = LangOptions::FPM_On; | 
|  | break; | 
|  | case TokFPAnnotValue::Fast: | 
|  | FPC = LangOptions::FPM_Fast; | 
|  | break; | 
|  | } | 
|  | Actions.ActOnPragmaFPContract(FPC); | 
|  | } | 
|  | ConsumeAnnotationToken(); | 
|  | } | 
|  |  | 
|  | /// Parses loop or unroll pragma hint value and fills in Info. | 
|  | static bool ParseLoopHintValue(Preprocessor &PP, Token &Tok, Token PragmaName, | 
|  | Token Option, bool ValueInParens, | 
|  | PragmaLoopHintInfo &Info) { | 
|  | SmallVector<Token, 1> ValueList; | 
|  | int OpenParens = ValueInParens ? 1 : 0; | 
|  | // Read constant expression. | 
|  | while (Tok.isNot(tok::eod)) { | 
|  | if (Tok.is(tok::l_paren)) | 
|  | OpenParens++; | 
|  | else if (Tok.is(tok::r_paren)) { | 
|  | OpenParens--; | 
|  | if (OpenParens == 0 && ValueInParens) | 
|  | break; | 
|  | } | 
|  |  | 
|  | ValueList.push_back(Tok); | 
|  | PP.Lex(Tok); | 
|  | } | 
|  |  | 
|  | if (ValueInParens) { | 
|  | // Read ')' | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | 
|  | return true; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  | } | 
|  |  | 
|  | Token EOFTok; | 
|  | EOFTok.startToken(); | 
|  | EOFTok.setKind(tok::eof); | 
|  | EOFTok.setLocation(Tok.getLocation()); | 
|  | ValueList.push_back(EOFTok); // Terminates expression for parsing. | 
|  |  | 
|  | Info.Toks = llvm::makeArrayRef(ValueList).copy(PP.getPreprocessorAllocator()); | 
|  |  | 
|  | Info.PragmaName = PragmaName; | 
|  | Info.Option = Option; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Handle the \#pragma clang loop directive. | 
|  | ///  #pragma clang 'loop' loop-hints | 
|  | /// | 
|  | ///  loop-hints: | 
|  | ///    loop-hint loop-hints[opt] | 
|  | /// | 
|  | ///  loop-hint: | 
|  | ///    'vectorize' '(' loop-hint-keyword ')' | 
|  | ///    'interleave' '(' loop-hint-keyword ')' | 
|  | ///    'unroll' '(' unroll-hint-keyword ')' | 
|  | ///    'vectorize_predicate' '(' loop-hint-keyword ')' | 
|  | ///    'vectorize_width' '(' loop-hint-value ')' | 
|  | ///    'interleave_count' '(' loop-hint-value ')' | 
|  | ///    'unroll_count' '(' loop-hint-value ')' | 
|  | ///    'pipeline' '(' disable ')' | 
|  | ///    'pipeline_initiation_interval' '(' loop-hint-value ')' | 
|  | /// | 
|  | ///  loop-hint-keyword: | 
|  | ///    'enable' | 
|  | ///    'disable' | 
|  | ///    'assume_safety' | 
|  | /// | 
|  | ///  unroll-hint-keyword: | 
|  | ///    'enable' | 
|  | ///    'disable' | 
|  | ///    'full' | 
|  | /// | 
|  | ///  loop-hint-value: | 
|  | ///    constant-expression | 
|  | /// | 
|  | /// Specifying vectorize(enable) or vectorize_width(_value_) instructs llvm to | 
|  | /// try vectorizing the instructions of the loop it precedes. Specifying | 
|  | /// interleave(enable) or interleave_count(_value_) instructs llvm to try | 
|  | /// interleaving multiple iterations of the loop it precedes. The width of the | 
|  | /// vector instructions is specified by vectorize_width() and the number of | 
|  | /// interleaved loop iterations is specified by interleave_count(). Specifying a | 
|  | /// value of 1 effectively disables vectorization/interleaving, even if it is | 
|  | /// possible and profitable, and 0 is invalid. The loop vectorizer currently | 
|  | /// only works on inner loops. | 
|  | /// | 
|  | /// The unroll and unroll_count directives control the concatenation | 
|  | /// unroller. Specifying unroll(enable) instructs llvm to unroll the loop | 
|  | /// completely if the trip count is known at compile time and unroll partially | 
|  | /// if the trip count is not known.  Specifying unroll(full) is similar to | 
|  | /// unroll(enable) but will unroll the loop only if the trip count is known at | 
|  | /// compile time.  Specifying unroll(disable) disables unrolling for the | 
|  | /// loop. Specifying unroll_count(_value_) instructs llvm to try to unroll the | 
|  | /// loop the number of times indicated by the value. | 
|  | void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | // Incoming token is "loop" from "#pragma clang loop". | 
|  | Token PragmaName = Tok; | 
|  | SmallVector<Token, 1> TokenList; | 
|  |  | 
|  | // Lex the optimization option and verify it is an identifier. | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::identifier)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) | 
|  | << /*MissingOption=*/true << ""; | 
|  | return; | 
|  | } | 
|  |  | 
|  | while (Tok.is(tok::identifier)) { | 
|  | Token Option = Tok; | 
|  | IdentifierInfo *OptionInfo = Tok.getIdentifierInfo(); | 
|  |  | 
|  | bool OptionValid = llvm::StringSwitch<bool>(OptionInfo->getName()) | 
|  | .Case("vectorize", true) | 
|  | .Case("interleave", true) | 
|  | .Case("unroll", true) | 
|  | .Case("distribute", true) | 
|  | .Case("vectorize_predicate", true) | 
|  | .Case("vectorize_width", true) | 
|  | .Case("interleave_count", true) | 
|  | .Case("unroll_count", true) | 
|  | .Case("pipeline", true) | 
|  | .Case("pipeline_initiation_interval", true) | 
|  | .Default(false); | 
|  | if (!OptionValid) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) | 
|  | << /*MissingOption=*/false << OptionInfo; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | // Read '(' | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; | 
|  | if (ParseLoopHintValue(PP, Tok, PragmaName, Option, /*ValueInParens=*/true, | 
|  | *Info)) | 
|  | return; | 
|  |  | 
|  | // Generate the loop hint token. | 
|  | Token LoopHintTok; | 
|  | LoopHintTok.startToken(); | 
|  | LoopHintTok.setKind(tok::annot_pragma_loop_hint); | 
|  | LoopHintTok.setLocation(PragmaName.getLocation()); | 
|  | LoopHintTok.setAnnotationEndLoc(PragmaName.getLocation()); | 
|  | LoopHintTok.setAnnotationValue(static_cast<void *>(Info)); | 
|  | TokenList.push_back(LoopHintTok); | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "clang loop"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | auto TokenArray = std::make_unique<Token[]>(TokenList.size()); | 
|  | std::copy(TokenList.begin(), TokenList.end(), TokenArray.get()); | 
|  |  | 
|  | PP.EnterTokenStream(std::move(TokenArray), TokenList.size(), | 
|  | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | /// Handle the loop unroll optimization pragmas. | 
|  | ///  #pragma unroll | 
|  | ///  #pragma unroll unroll-hint-value | 
|  | ///  #pragma unroll '(' unroll-hint-value ')' | 
|  | ///  #pragma nounroll | 
|  | ///  #pragma unroll_and_jam | 
|  | ///  #pragma unroll_and_jam unroll-hint-value | 
|  | ///  #pragma unroll_and_jam '(' unroll-hint-value ')' | 
|  | ///  #pragma nounroll_and_jam | 
|  | /// | 
|  | ///  unroll-hint-value: | 
|  | ///    constant-expression | 
|  | /// | 
|  | /// Loop unrolling hints can be specified with '#pragma unroll' or | 
|  | /// '#pragma nounroll'. '#pragma unroll' can take a numeric argument optionally | 
|  | /// contained in parentheses. With no argument the directive instructs llvm to | 
|  | /// try to unroll the loop completely. A positive integer argument can be | 
|  | /// specified to indicate the number of times the loop should be unrolled.  To | 
|  | /// maximize compatibility with other compilers the unroll count argument can be | 
|  | /// specified with or without parentheses.  Specifying, '#pragma nounroll' | 
|  | /// disables unrolling of the loop. | 
|  | void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | // Incoming token is "unroll" for "#pragma unroll", or "nounroll" for | 
|  | // "#pragma nounroll". | 
|  | Token PragmaName = Tok; | 
|  | PP.Lex(Tok); | 
|  | auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; | 
|  | if (Tok.is(tok::eod)) { | 
|  | // nounroll or unroll pragma without an argument. | 
|  | Info->PragmaName = PragmaName; | 
|  | Info->Option.startToken(); | 
|  | } else if (PragmaName.getIdentifierInfo()->getName() == "nounroll" || | 
|  | PragmaName.getIdentifierInfo()->getName() == "nounroll_and_jam") { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << PragmaName.getIdentifierInfo()->getName(); | 
|  | return; | 
|  | } else { | 
|  | // Unroll pragma with an argument: "#pragma unroll N" or | 
|  | // "#pragma unroll(N)". | 
|  | // Read '(' if it exists. | 
|  | bool ValueInParens = Tok.is(tok::l_paren); | 
|  | if (ValueInParens) | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | Token Option; | 
|  | Option.startToken(); | 
|  | if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info)) | 
|  | return; | 
|  |  | 
|  | // In CUDA, the argument to '#pragma unroll' should not be contained in | 
|  | // parentheses. | 
|  | if (PP.getLangOpts().CUDA && ValueInParens) | 
|  | PP.Diag(Info->Toks[0].getLocation(), | 
|  | diag::warn_pragma_unroll_cuda_value_in_parens); | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "unroll"; | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Generate the hint token. | 
|  | auto TokenArray = std::make_unique<Token[]>(1); | 
|  | TokenArray[0].startToken(); | 
|  | TokenArray[0].setKind(tok::annot_pragma_loop_hint); | 
|  | TokenArray[0].setLocation(PragmaName.getLocation()); | 
|  | TokenArray[0].setAnnotationEndLoc(PragmaName.getLocation()); | 
|  | TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); | 
|  | PP.EnterTokenStream(std::move(TokenArray), 1, | 
|  | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | /// Handle the Microsoft \#pragma intrinsic extension. | 
|  | /// | 
|  | /// The syntax is: | 
|  | /// \code | 
|  | ///  #pragma intrinsic(memset) | 
|  | ///  #pragma intrinsic(strlen, memcpy) | 
|  | /// \endcode | 
|  | /// | 
|  | /// Pragma intrisic tells the compiler to use a builtin version of the | 
|  | /// function. Clang does it anyway, so the pragma doesn't really do anything. | 
|  | /// Anyway, we emit a warning if the function specified in \#pragma intrinsic | 
|  | /// isn't an intrinsic in clang and suggest to include intrin.h. | 
|  | void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) | 
|  | << "intrinsic"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H"); | 
|  |  | 
|  | while (Tok.is(tok::identifier)) { | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (!II->getBuiltinID()) | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin) | 
|  | << II << SuggestIntrinH; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (Tok.isNot(tok::comma)) | 
|  | break; | 
|  | PP.Lex(Tok); | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) | 
|  | << "intrinsic"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "intrinsic"; | 
|  | } | 
|  |  | 
|  | // #pragma optimize("gsty", on|off) | 
|  | void PragmaMSOptimizeHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | SourceLocation StartLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << "optimize"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::string_literal)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_string) << "optimize"; | 
|  | return; | 
|  | } | 
|  | // We could syntax check the string but it's probably not worth the effort. | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::comma)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_comma) << "optimize"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.is(tok::eod) || Tok.is(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_missing_argument) | 
|  | << "optimize" << /*Expected=*/true << "'on' or 'off'"; | 
|  | return; | 
|  | } | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (!II || (!II->isStr("on") && !II->isStr("off"))) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_argument) | 
|  | << PP.getSpelling(Tok) << "optimize" << /*Expected=*/true | 
|  | << "'on' or 'off'"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) << "optimize"; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "optimize"; | 
|  | return; | 
|  | } | 
|  | PP.Diag(StartLoc, diag::warn_pragma_optimize); | 
|  | } | 
|  |  | 
|  | void PragmaForceCUDAHostDeviceHandler::HandlePragma( | 
|  | Preprocessor &PP, PragmaIntroducer Introducer, Token &Tok) { | 
|  | Token FirstTok = Tok; | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | IdentifierInfo *Info = Tok.getIdentifierInfo(); | 
|  | if (!Info || (!Info->isStr("begin") && !Info->isStr("end"))) { | 
|  | PP.Diag(FirstTok.getLocation(), | 
|  | diag::warn_pragma_force_cuda_host_device_bad_arg); | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Info->isStr("begin")) | 
|  | Actions.PushForceCUDAHostDevice(); | 
|  | else if (!Actions.PopForceCUDAHostDevice()) | 
|  | PP.Diag(FirstTok.getLocation(), | 
|  | diag::err_pragma_cannot_end_force_cuda_host_device); | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | if (!Tok.is(tok::eod)) | 
|  | PP.Diag(FirstTok.getLocation(), | 
|  | diag::warn_pragma_force_cuda_host_device_bad_arg); | 
|  | } | 
|  |  | 
|  | /// Handle the #pragma clang attribute directive. | 
|  | /// | 
|  | /// The syntax is: | 
|  | /// \code | 
|  | ///  #pragma clang attribute push (attribute, subject-set) | 
|  | ///  #pragma clang attribute push | 
|  | ///  #pragma clang attribute (attribute, subject-set) | 
|  | ///  #pragma clang attribute pop | 
|  | /// \endcode | 
|  | /// | 
|  | /// There are also 'namespace' variants of push and pop directives. The bare | 
|  | /// '#pragma clang attribute (attribute, subject-set)' version doesn't require a | 
|  | /// namespace, since it always applies attributes to the most recently pushed | 
|  | /// group, regardless of namespace. | 
|  | /// \code | 
|  | ///  #pragma clang attribute namespace.push (attribute, subject-set) | 
|  | ///  #pragma clang attribute namespace.push | 
|  | ///  #pragma clang attribute namespace.pop | 
|  | /// \endcode | 
|  | /// | 
|  | /// The subject-set clause defines the set of declarations which receive the | 
|  | /// attribute. Its exact syntax is described in the LanguageExtensions document | 
|  | /// in Clang's documentation. | 
|  | /// | 
|  | /// This directive instructs the compiler to begin/finish applying the specified | 
|  | /// attribute to the set of attribute-specific declarations in the active range | 
|  | /// of the pragma. | 
|  | void PragmaAttributeHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &FirstToken) { | 
|  | Token Tok; | 
|  | PP.Lex(Tok); | 
|  | auto *Info = new (PP.getPreprocessorAllocator()) | 
|  | PragmaAttributeInfo(AttributesForPragmaAttribute); | 
|  |  | 
|  | // Parse the optional namespace followed by a period. | 
|  | if (Tok.is(tok::identifier)) { | 
|  | IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (!II->isStr("push") && !II->isStr("pop")) { | 
|  | Info->Namespace = II; | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | if (!Tok.is(tok::period)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_period) | 
|  | << II; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!Tok.isOneOf(tok::identifier, tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), | 
|  | diag::err_pragma_attribute_expected_push_pop_paren); | 
|  | return; | 
|  | } | 
|  |  | 
|  | // Determine what action this pragma clang attribute represents. | 
|  | if (Tok.is(tok::l_paren)) { | 
|  | if (Info->Namespace) { | 
|  | PP.Diag(Tok.getLocation(), | 
|  | diag::err_pragma_attribute_namespace_on_attribute); | 
|  | PP.Diag(Tok.getLocation(), | 
|  | diag::note_pragma_attribute_namespace_on_attribute); | 
|  | return; | 
|  | } | 
|  | Info->Action = PragmaAttributeInfo::Attribute; | 
|  | } else { | 
|  | const IdentifierInfo *II = Tok.getIdentifierInfo(); | 
|  | if (II->isStr("push")) | 
|  | Info->Action = PragmaAttributeInfo::Push; | 
|  | else if (II->isStr("pop")) | 
|  | Info->Action = PragmaAttributeInfo::Pop; | 
|  | else { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_invalid_argument) | 
|  | << PP.getSpelling(Tok); | 
|  | return; | 
|  | } | 
|  |  | 
|  | PP.Lex(Tok); | 
|  | } | 
|  |  | 
|  | // Parse the actual attribute. | 
|  | if ((Info->Action == PragmaAttributeInfo::Push && Tok.isNot(tok::eod)) || | 
|  | Info->Action == PragmaAttributeInfo::Attribute) { | 
|  | if (Tok.isNot(tok::l_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; | 
|  | return; | 
|  | } | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | // Lex the attribute tokens. | 
|  | SmallVector<Token, 16> AttributeTokens; | 
|  | int OpenParens = 1; | 
|  | while (Tok.isNot(tok::eod)) { | 
|  | if (Tok.is(tok::l_paren)) | 
|  | OpenParens++; | 
|  | else if (Tok.is(tok::r_paren)) { | 
|  | OpenParens--; | 
|  | if (OpenParens == 0) | 
|  | break; | 
|  | } | 
|  |  | 
|  | AttributeTokens.push_back(Tok); | 
|  | PP.Lex(Tok); | 
|  | } | 
|  |  | 
|  | if (AttributeTokens.empty()) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_attribute_expected_attribute); | 
|  | return; | 
|  | } | 
|  | if (Tok.isNot(tok::r_paren)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; | 
|  | return; | 
|  | } | 
|  | SourceLocation EndLoc = Tok.getLocation(); | 
|  | PP.Lex(Tok); | 
|  |  | 
|  | // Terminate the attribute for parsing. | 
|  | Token EOFTok; | 
|  | EOFTok.startToken(); | 
|  | EOFTok.setKind(tok::eof); | 
|  | EOFTok.setLocation(EndLoc); | 
|  | AttributeTokens.push_back(EOFTok); | 
|  |  | 
|  | Info->Tokens = | 
|  | llvm::makeArrayRef(AttributeTokens).copy(PP.getPreprocessorAllocator()); | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "clang attribute"; | 
|  |  | 
|  | // Generate the annotated pragma token. | 
|  | auto TokenArray = std::make_unique<Token[]>(1); | 
|  | TokenArray[0].startToken(); | 
|  | TokenArray[0].setKind(tok::annot_pragma_attribute); | 
|  | TokenArray[0].setLocation(FirstToken.getLocation()); | 
|  | TokenArray[0].setAnnotationEndLoc(FirstToken.getLocation()); | 
|  | TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); | 
|  | PP.EnterTokenStream(std::move(TokenArray), 1, | 
|  | /*DisableMacroExpansion=*/false, /*IsReinject=*/false); | 
|  | } | 
|  |  | 
|  | // Handle '#pragma clang max_tokens 12345'. | 
|  | void PragmaMaxTokensHereHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) | 
|  | << "clang max_tokens_here" << /*Expected=*/true << "integer"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | uint64_t MaxTokens; | 
|  | if (Tok.isNot(tok::numeric_constant) || | 
|  | !PP.parseSimpleIntegerLiteral(Tok, MaxTokens)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_integer) | 
|  | << "clang max_tokens_here"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "clang max_tokens_here"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (PP.getTokenCount() > MaxTokens) { | 
|  | PP.Diag(Loc, diag::warn_max_tokens) | 
|  | << PP.getTokenCount() << (unsigned)MaxTokens; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Handle '#pragma clang max_tokens_total 12345'. | 
|  | void PragmaMaxTokensTotalHandler::HandlePragma(Preprocessor &PP, | 
|  | PragmaIntroducer Introducer, | 
|  | Token &Tok) { | 
|  | PP.Lex(Tok); | 
|  | if (Tok.is(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) | 
|  | << "clang max_tokens_total" << /*Expected=*/true << "integer"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | SourceLocation Loc = Tok.getLocation(); | 
|  | uint64_t MaxTokens; | 
|  | if (Tok.isNot(tok::numeric_constant) || | 
|  | !PP.parseSimpleIntegerLiteral(Tok, MaxTokens)) { | 
|  | PP.Diag(Tok.getLocation(), diag::err_pragma_expected_integer) | 
|  | << "clang max_tokens_total"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (Tok.isNot(tok::eod)) { | 
|  | PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) | 
|  | << "clang max_tokens_total"; | 
|  | return; | 
|  | } | 
|  |  | 
|  | PP.overrideMaxTokens(MaxTokens, Loc); | 
|  | } |