| //===--- ParsePragma.cpp - Language specific pragma parsing ---------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the language specific #pragma handlers. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "RAIIObjectsForParser.h" |
| #include "clang/Basic/TargetInfo.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Parse/ParseDiagnostic.h" |
| #include "clang/Parse/Parser.h" |
| #include "clang/Sema/LoopHint.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, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaGCCVisibilityHandler : public PragmaHandler { |
| explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaOptionsHandler : public PragmaHandler { |
| explicit PragmaOptionsHandler() : PragmaHandler("options") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaPackHandler : public PragmaHandler { |
| explicit PragmaPackHandler() : PragmaHandler("pack") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaMSStructHandler : public PragmaHandler { |
| explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaUnusedHandler : public PragmaHandler { |
| PragmaUnusedHandler() : PragmaHandler("unused") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaWeakHandler : public PragmaHandler { |
| explicit PragmaWeakHandler() : PragmaHandler("weak") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaRedefineExtnameHandler : public PragmaHandler { |
| explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaOpenCLExtensionHandler : public PragmaHandler { |
| PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| |
| struct PragmaFPContractHandler : public PragmaHandler { |
| PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaNoOpenMPHandler : public PragmaHandler { |
| PragmaNoOpenMPHandler() : PragmaHandler("omp") { } |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaOpenMPHandler : public PragmaHandler { |
| PragmaOpenMPHandler() : PragmaHandler("omp") { } |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| /// PragmaCommentHandler - "\#pragma comment ...". |
| struct PragmaCommentHandler : public PragmaHandler { |
| PragmaCommentHandler(Sema &Actions) |
| : PragmaHandler("comment"), Actions(Actions) {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| private: |
| Sema &Actions; |
| }; |
| |
| struct PragmaDetectMismatchHandler : public PragmaHandler { |
| PragmaDetectMismatchHandler(Sema &Actions) |
| : PragmaHandler("detect_mismatch"), Actions(Actions) {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| private: |
| Sema &Actions; |
| }; |
| |
| struct PragmaMSPointersToMembers : public PragmaHandler { |
| explicit PragmaMSPointersToMembers() : PragmaHandler("pointers_to_members") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaMSVtorDisp : public PragmaHandler { |
| explicit PragmaMSVtorDisp() : PragmaHandler("vtordisp") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaMSPragma : public PragmaHandler { |
| explicit PragmaMSPragma(const char *name) : PragmaHandler(name) {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind 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, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| private: |
| Sema &Actions; |
| }; |
| |
| struct PragmaLoopHintHandler : public PragmaHandler { |
| PragmaLoopHintHandler() : PragmaHandler("loop") {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| struct PragmaUnrollHintHandler : public PragmaHandler { |
| PragmaUnrollHintHandler(const char *name) : PragmaHandler(name) {} |
| void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, |
| Token &FirstToken) override; |
| }; |
| |
| } // end namespace |
| |
| void Parser::initializePragmaHandlers() { |
| AlignHandler.reset(new PragmaAlignHandler()); |
| PP.AddPragmaHandler(AlignHandler.get()); |
| |
| GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler()); |
| PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get()); |
| |
| OptionsHandler.reset(new PragmaOptionsHandler()); |
| PP.AddPragmaHandler(OptionsHandler.get()); |
| |
| PackHandler.reset(new PragmaPackHandler()); |
| PP.AddPragmaHandler(PackHandler.get()); |
| |
| MSStructHandler.reset(new PragmaMSStructHandler()); |
| PP.AddPragmaHandler(MSStructHandler.get()); |
| |
| UnusedHandler.reset(new PragmaUnusedHandler()); |
| PP.AddPragmaHandler(UnusedHandler.get()); |
| |
| WeakHandler.reset(new PragmaWeakHandler()); |
| PP.AddPragmaHandler(WeakHandler.get()); |
| |
| RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler()); |
| PP.AddPragmaHandler(RedefineExtnameHandler.get()); |
| |
| FPContractHandler.reset(new PragmaFPContractHandler()); |
| PP.AddPragmaHandler("STDC", FPContractHandler.get()); |
| |
| if (getLangOpts().OpenCL) { |
| OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler()); |
| PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); |
| |
| PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); |
| } |
| if (getLangOpts().OpenMP) |
| OpenMPHandler.reset(new PragmaOpenMPHandler()); |
| else |
| OpenMPHandler.reset(new PragmaNoOpenMPHandler()); |
| PP.AddPragmaHandler(OpenMPHandler.get()); |
| |
| if (getLangOpts().MicrosoftExt) { |
| MSCommentHandler.reset(new PragmaCommentHandler(Actions)); |
| PP.AddPragmaHandler(MSCommentHandler.get()); |
| MSDetectMismatchHandler.reset(new PragmaDetectMismatchHandler(Actions)); |
| PP.AddPragmaHandler(MSDetectMismatchHandler.get()); |
| MSPointersToMembers.reset(new PragmaMSPointersToMembers()); |
| PP.AddPragmaHandler(MSPointersToMembers.get()); |
| MSVtorDisp.reset(new PragmaMSVtorDisp()); |
| PP.AddPragmaHandler(MSVtorDisp.get()); |
| MSInitSeg.reset(new PragmaMSPragma("init_seg")); |
| PP.AddPragmaHandler(MSInitSeg.get()); |
| MSDataSeg.reset(new PragmaMSPragma("data_seg")); |
| PP.AddPragmaHandler(MSDataSeg.get()); |
| MSBSSSeg.reset(new PragmaMSPragma("bss_seg")); |
| PP.AddPragmaHandler(MSBSSSeg.get()); |
| MSConstSeg.reset(new PragmaMSPragma("const_seg")); |
| PP.AddPragmaHandler(MSConstSeg.get()); |
| MSCodeSeg.reset(new PragmaMSPragma("code_seg")); |
| PP.AddPragmaHandler(MSCodeSeg.get()); |
| MSSection.reset(new PragmaMSPragma("section")); |
| PP.AddPragmaHandler(MSSection.get()); |
| } |
| |
| OptimizeHandler.reset(new PragmaOptimizeHandler(Actions)); |
| PP.AddPragmaHandler("clang", OptimizeHandler.get()); |
| |
| LoopHintHandler.reset(new PragmaLoopHintHandler()); |
| PP.AddPragmaHandler("clang", LoopHintHandler.get()); |
| |
| UnrollHintHandler.reset(new PragmaUnrollHintHandler("unroll")); |
| PP.AddPragmaHandler(UnrollHintHandler.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) { |
| PP.RemovePragmaHandler(MSCommentHandler.get()); |
| MSCommentHandler.reset(); |
| 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("STDC", FPContractHandler.get()); |
| FPContractHandler.reset(); |
| |
| PP.RemovePragmaHandler("clang", OptimizeHandler.get()); |
| OptimizeHandler.reset(); |
| |
| PP.RemovePragmaHandler("clang", LoopHintHandler.get()); |
| LoopHintHandler.reset(); |
| |
| PP.RemovePragmaHandler(UnrollHintHandler.get()); |
| UnrollHintHandler.reset(); |
| } |
| |
| /// \brief 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 = ConsumeToken(); |
| 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 = ConsumeToken(); |
| Actions.ActOnPragmaVisibility(VisType, VisLoc); |
| } |
| |
| struct PragmaPackInfo { |
| Sema::PragmaPackKind Kind; |
| IdentifierInfo *Name; |
| Token Alignment; |
| SourceLocation LParenLoc; |
| SourceLocation RParenLoc; |
| }; |
| |
| void Parser::HandlePragmaPack() { |
| assert(Tok.is(tok::annot_pragma_pack)); |
| PragmaPackInfo *Info = |
| static_cast<PragmaPackInfo *>(Tok.getAnnotationValue()); |
| SourceLocation PragmaLoc = ConsumeToken(); |
| ExprResult Alignment; |
| if (Info->Alignment.is(tok::numeric_constant)) { |
| Alignment = Actions.ActOnNumericConstant(Info->Alignment); |
| if (Alignment.isInvalid()) |
| return; |
| } |
| Actions.ActOnPragmaPack(Info->Kind, Info->Name, Alignment.get(), PragmaLoc, |
| Info->LParenLoc, Info->RParenLoc); |
| } |
| |
| void Parser::HandlePragmaMSStruct() { |
| assert(Tok.is(tok::annot_pragma_msstruct)); |
| Sema::PragmaMSStructKind Kind = |
| static_cast<Sema::PragmaMSStructKind>( |
| reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); |
| Actions.ActOnPragmaMSStruct(Kind); |
| ConsumeToken(); // The annotation token. |
| } |
| |
| void Parser::HandlePragmaAlign() { |
| assert(Tok.is(tok::annot_pragma_align)); |
| Sema::PragmaOptionsAlignKind Kind = |
| static_cast<Sema::PragmaOptionsAlignKind>( |
| reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); |
| SourceLocation PragmaLoc = ConsumeToken(); |
| Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc); |
| } |
| |
| void Parser::HandlePragmaWeak() { |
| assert(Tok.is(tok::annot_pragma_weak)); |
| SourceLocation PragmaLoc = ConsumeToken(); |
| Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc, |
| Tok.getLocation()); |
| ConsumeToken(); // The weak name. |
| } |
| |
| void Parser::HandlePragmaWeakAlias() { |
| assert(Tok.is(tok::annot_pragma_weakalias)); |
| SourceLocation PragmaLoc = ConsumeToken(); |
| 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 = ConsumeToken(); |
| 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())); |
| Actions.ActOnPragmaFPContract(OOS); |
| ConsumeToken(); // The annotation token. |
| } |
| |
| StmtResult Parser::HandlePragmaCaptured() |
| { |
| assert(Tok.is(tok::annot_pragma_captured)); |
| ConsumeToken(); |
| |
| 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); |
| 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 { |
| typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData; |
| } |
| |
| void Parser::HandlePragmaOpenCLExtension() { |
| assert(Tok.is(tok::annot_pragma_opencl_extension)); |
| OpenCLExtData data = |
| OpenCLExtData::getFromOpaqueValue(Tok.getAnnotationValue()); |
| unsigned state = data.getInt(); |
| IdentifierInfo *ename = data.getPointer(); |
| SourceLocation NameLoc = Tok.getLocation(); |
| ConsumeToken(); // The annotation token. |
| |
| OpenCLOptions &f = Actions.getOpenCLOptions(); |
| // 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 (state == 0 && ename->isStr("all")) { |
| #define OPENCLEXT(nm) f.nm = 0; |
| #include "clang/Basic/OpenCLExtensions.def" |
| } |
| #define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } |
| #include "clang/Basic/OpenCLExtensions.def" |
| else { |
| PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; |
| return; |
| } |
| } |
| |
| 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 = ConsumeToken(); // The annotation token. |
| 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::PragmaVtorDispKind Kind = |
| static_cast<Sema::PragmaVtorDispKind>((Value >> 16) & 0xFFFF); |
| MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF); |
| SourceLocation PragmaLoc = ConsumeToken(); // The annotation token. |
| Actions.ActOnPragmaMSVtorDisp(Kind, 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<Token*, size_t> *)Tok.getAnnotationValue(); |
| PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true); |
| SourceLocation PragmaLocation = ConsumeToken(); // The annotation token. |
| 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 = 0; |
| while (Tok.is(tok::comma)) { |
| PP.Lex(Tok); // , |
| if (!Tok.isAnyIdentifier()) { |
| PP.Diag(PragmaLocation, diag::warn_pragma_expected_action_or_r_paren) |
| << PragmaName; |
| return false; |
| } |
| Sema::PragmaSectionFlag Flag = |
| llvm::StringSwitch<Sema::PragmaSectionFlag>( |
| Tok.getIdentifierInfo()->getName()) |
| .Case("read", Sema::PSF_Read) |
| .Case("write", Sema::PSF_Write) |
| .Case("execute", Sema::PSF_Execute) |
| .Case("shared", Sema::PSF_Invalid) |
| .Case("nopage", Sema::PSF_Invalid) |
| .Case("nocache", Sema::PSF_Invalid) |
| .Case("discard", Sema::PSF_Invalid) |
| .Case("remove", Sema::PSF_Invalid) |
| .Default(Sema::PSF_None); |
| if (Flag == Sema::PSF_None || Flag == Sema::PSF_Invalid) { |
| PP.Diag(PragmaLocation, Flag == Sema::PSF_None |
| ? diag::warn_pragma_invalid_specific_action |
| : diag::warn_pragma_unsupported_action) |
| << PragmaName << Tok.getIdentifierInfo()->getName(); |
| return false; |
| } |
| SectionFlags |= Flag; |
| PP.Lex(Tok); // Identifier |
| } |
| 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; |
| } |
| |
| struct PragmaLoopHintInfo { |
| Token PragmaName; |
| Token Option; |
| Token Value; |
| bool HasValue; |
| }; |
| |
| LoopHint Parser::HandlePragmaLoopHint() { |
| assert(Tok.is(tok::annot_pragma_loop_hint)); |
| PragmaLoopHintInfo *Info = |
| static_cast<PragmaLoopHintInfo *>(Tok.getAnnotationValue()); |
| |
| LoopHint Hint; |
| Hint.PragmaNameLoc = |
| IdentifierLoc::create(Actions.Context, Info->PragmaName.getLocation(), |
| Info->PragmaName.getIdentifierInfo()); |
| Hint.OptionLoc = |
| IdentifierLoc::create(Actions.Context, Info->Option.getLocation(), |
| Info->Option.getIdentifierInfo()); |
| if (Info->HasValue) { |
| Hint.Range = |
| SourceRange(Info->Option.getLocation(), Info->Value.getLocation()); |
| Hint.ValueLoc = |
| IdentifierLoc::create(Actions.Context, Info->Value.getLocation(), |
| Info->Value.getIdentifierInfo()); |
| |
| // FIXME: We should allow non-type template parameters for the loop hint |
| // value. See bug report #19610 |
| if (Info->Value.is(tok::numeric_constant)) |
| Hint.ValueExpr = Actions.ActOnNumericConstant(Info->Value).get(); |
| else |
| Hint.ValueExpr = nullptr; |
| } else { |
| Hint.Range = SourceRange(Info->PragmaName.getLocation()); |
| Hint.ValueLoc = nullptr; |
| Hint.ValueExpr = nullptr; |
| } |
| |
| return Hint; |
| } |
| |
| // #pragma GCC visibility comes in two variants: |
| // 'push' '(' [visibility] ')' |
| // 'pop' |
| void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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; |
| } |
| PP.LexUnexpandedToken(Tok); |
| if (Tok.isNot(tok::eod)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) |
| << "visibility"; |
| return; |
| } |
| |
| Token *Toks = new Token[1]; |
| Toks[0].startToken(); |
| Toks[0].setKind(tok::annot_pragma_vis); |
| Toks[0].setLocation(VisLoc); |
| Toks[0].setAnnotationValue( |
| const_cast<void*>(static_cast<const void*>(VisType))); |
| PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, |
| /*OwnsTokens=*/true); |
| } |
| |
| // #pragma pack(...) comes in the following delicious flavors: |
| // pack '(' [integer] ')' |
| // pack '(' 'show' ')' |
| // pack '(' ('push' | 'pop') [',' identifier] [, integer] ')' |
| void PragmaPackHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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::PragmaPackKind Kind = Sema::PPK_Default; |
| IdentifierInfo *Name = nullptr; |
| Token Alignment; |
| Alignment.startToken(); |
| SourceLocation LParenLoc = Tok.getLocation(); |
| 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) |
| if (PP.getLangOpts().ApplePragmaPack) |
| Kind = Sema::PPK_Push; |
| } else if (Tok.is(tok::identifier)) { |
| const IdentifierInfo *II = Tok.getIdentifierInfo(); |
| if (II->isStr("show")) { |
| Kind = Sema::PPK_Show; |
| PP.Lex(Tok); |
| } else { |
| if (II->isStr("push")) { |
| Kind = Sema::PPK_Push; |
| } else if (II->isStr("pop")) { |
| Kind = Sema::PPK_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)) { |
| Alignment = Tok; |
| |
| PP.Lex(Tok); |
| } else if (Tok.is(tok::identifier)) { |
| Name = Tok.getIdentifierInfo(); |
| 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; |
| } |
| |
| 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). |
| Kind = Sema::PPK_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 = |
| (PragmaPackInfo*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(PragmaPackInfo), llvm::alignOf<PragmaPackInfo>()); |
| new (Info) PragmaPackInfo(); |
| Info->Kind = Kind; |
| Info->Name = Name; |
| Info->Alignment = Alignment; |
| Info->LParenLoc = LParenLoc; |
| Info->RParenLoc = RParenLoc; |
| |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 1, llvm::alignOf<Token>()); |
| new (Toks) Token(); |
| Toks[0].startToken(); |
| Toks[0].setKind(tok::annot_pragma_pack); |
| Toks[0].setLocation(PackLoc); |
| Toks[0].setAnnotationValue(static_cast<void*>(Info)); |
| PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, |
| /*OwnsTokens=*/false); |
| } |
| |
| // #pragma ms_struct on |
| // #pragma ms_struct off |
| void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &MSStructTok) { |
| Sema::PragmaMSStructKind Kind = Sema::PMSST_OFF; |
| |
| Token Tok; |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::identifier)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_ms_struct); |
| return; |
| } |
| const IdentifierInfo *II = Tok.getIdentifierInfo(); |
| if (II->isStr("on")) { |
| Kind = Sema::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; |
| } |
| |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 1, llvm::alignOf<Token>()); |
| new (Toks) Token(); |
| Toks[0].startToken(); |
| Toks[0].setKind(tok::annot_pragma_msstruct); |
| Toks[0].setLocation(MSStructTok.getLocation()); |
| Toks[0].setAnnotationValue(reinterpret_cast<void*>( |
| static_cast<uintptr_t>(Kind))); |
| PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, |
| /*OwnsTokens=*/false); |
| } |
| |
| // #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; |
| } |
| |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::eod)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) |
| << (IsOptions ? "options" : "align"); |
| return; |
| } |
| |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 1, llvm::alignOf<Token>()); |
| new (Toks) Token(); |
| Toks[0].startToken(); |
| Toks[0].setKind(tok::annot_pragma_align); |
| Toks[0].setLocation(FirstTok.getLocation()); |
| Toks[0].setAnnotationValue(reinterpret_cast<void*>( |
| static_cast<uintptr_t>(Kind))); |
| PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, |
| /*OwnsTokens=*/false); |
| } |
| |
| void PragmaAlignHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &AlignTok) { |
| ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false); |
| } |
| |
| void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &OptionsTok) { |
| ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true); |
| } |
| |
| // #pragma unused(identifier) |
| void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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. |
| |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 2 * Identifiers.size(), llvm::alignOf<Token>()); |
| 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, 2*Identifiers.size(), |
| /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); |
| } |
| |
| // #pragma weak identifier |
| // #pragma weak identifier '=' identifier |
| void PragmaWeakHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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) { |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 3, llvm::alignOf<Token>()); |
| Token &pragmaUnusedTok = Toks[0]; |
| pragmaUnusedTok.startToken(); |
| pragmaUnusedTok.setKind(tok::annot_pragma_weakalias); |
| pragmaUnusedTok.setLocation(WeakLoc); |
| Toks[1] = WeakName; |
| Toks[2] = AliasName; |
| PP.EnterTokenStream(Toks, 3, |
| /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); |
| } else { |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 2, llvm::alignOf<Token>()); |
| Token &pragmaUnusedTok = Toks[0]; |
| pragmaUnusedTok.startToken(); |
| pragmaUnusedTok.setKind(tok::annot_pragma_weak); |
| pragmaUnusedTok.setLocation(WeakLoc); |
| Toks[1] = WeakName; |
| PP.EnterTokenStream(Toks, 2, |
| /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); |
| } |
| } |
| |
| // #pragma redefine_extname identifier identifier |
| void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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; |
| } |
| |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 3, llvm::alignOf<Token>()); |
| Token &pragmaRedefTok = Toks[0]; |
| pragmaRedefTok.startToken(); |
| pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname); |
| pragmaRedefTok.setLocation(RedefLoc); |
| Toks[1] = RedefName; |
| Toks[2] = AliasName; |
| PP.EnterTokenStream(Toks, 3, |
| /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); |
| } |
| |
| |
| void |
| PragmaFPContractHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &Tok) { |
| tok::OnOffSwitch OOS; |
| if (PP.LexOnOffSwitch(OOS)) |
| return; |
| |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 1, llvm::alignOf<Token>()); |
| new (Toks) Token(); |
| Toks[0].startToken(); |
| Toks[0].setKind(tok::annot_pragma_fp_contract); |
| Toks[0].setLocation(Tok.getLocation()); |
| Toks[0].setAnnotationValue(reinterpret_cast<void*>( |
| static_cast<uintptr_t>(OOS))); |
| PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, |
| /*OwnsTokens=*/false); |
| } |
| |
| void |
| PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &Tok) { |
| PP.LexUnexpandedToken(Tok); |
| if (Tok.isNot(tok::identifier)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << |
| "OPENCL"; |
| return; |
| } |
| IdentifierInfo *ename = Tok.getIdentifierInfo(); |
| SourceLocation NameLoc = Tok.getLocation(); |
| |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::colon)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_colon) << ename; |
| return; |
| } |
| |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::identifier)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); |
| return; |
| } |
| IdentifierInfo *op = Tok.getIdentifierInfo(); |
| |
| unsigned state; |
| if (op->isStr("enable")) { |
| state = 1; |
| } else if (op->isStr("disable")) { |
| state = 0; |
| } else { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_enable_disable); |
| 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; |
| } |
| |
| OpenCLExtData data(ename, state); |
| Token *Toks = |
| (Token*) PP.getPreprocessorAllocator().Allocate( |
| sizeof(Token) * 1, llvm::alignOf<Token>()); |
| new (Toks) Token(); |
| Toks[0].startToken(); |
| Toks[0].setKind(tok::annot_pragma_opencl_extension); |
| Toks[0].setLocation(NameLoc); |
| Toks[0].setAnnotationValue(data.getOpaqueValue()); |
| PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, |
| /*OwnsTokens=*/false); |
| |
| if (PP.getPPCallbacks()) |
| PP.getPPCallbacks()->PragmaOpenCLExtension(NameLoc, ename, |
| StateLoc, state); |
| } |
| |
| /// \brief Handle '#pragma omp ...' when OpenMP is disabled. |
| /// |
| void |
| PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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(); |
| } |
| |
| /// \brief Handle '#pragma omp ...' when OpenMP is enabled. |
| /// |
| void |
| PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &FirstTok) { |
| SmallVector<Token, 16> Pragma; |
| Token Tok; |
| Tok.startToken(); |
| Tok.setKind(tok::annot_pragma_openmp); |
| Tok.setLocation(FirstTok.getLocation()); |
| |
| while (Tok.isNot(tok::eod)) { |
| Pragma.push_back(Tok); |
| PP.Lex(Tok); |
| } |
| SourceLocation EodLoc = Tok.getLocation(); |
| Tok.startToken(); |
| Tok.setKind(tok::annot_pragma_openmp_end); |
| Tok.setLocation(EodLoc); |
| Pragma.push_back(Tok); |
| |
| Token *Toks = new Token[Pragma.size()]; |
| std::copy(Pragma.begin(), Pragma.end(), Toks); |
| PP.EnterTokenStream(Toks, Pragma.size(), |
| /*DisableMacroExpansion=*/true, /*OwnsTokens=*/true); |
| } |
| |
| /// \brief 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, |
| PragmaIntroducerKind 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; |
| } |
| |
| 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.setAnnotationValue( |
| reinterpret_cast<void *>(static_cast<uintptr_t>(RepresentationMethod))); |
| PP.EnterToken(AnnotTok); |
| } |
| |
| /// \brief 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, |
| PragmaIntroducerKind 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::PragmaVtorDispKind Kind = Sema::PVDK_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); |
| Kind = Sema::PVDK_Push; |
| // not push, could be on/off |
| } else if (II->isStr("pop")) { |
| // #pragma vtordisp(pop) |
| PP.Lex(Tok); |
| Kind = Sema::PVDK_Pop; |
| } |
| // not push or pop, could be on/off |
| } else { |
| if (Tok.is(tok::r_paren)) { |
| // #pragma vtordisp() |
| Kind = Sema::PVDK_Reset; |
| } |
| } |
| |
| |
| uint64_t Value = 0; |
| if (Kind == Sema::PVDK_Push || Kind == Sema::PVDK_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; |
| } |
| 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.setAnnotationValue(reinterpret_cast<void *>( |
| static_cast<uintptr_t>((Kind << 16) | (Value & 0xFFFF)))); |
| PP.EnterToken(AnnotTok); |
| } |
| |
| /// \brief Handle all MS pragmas. Simply forwards the tokens after inserting |
| /// an annotation token. |
| void PragmaMSPragma::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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()); |
| 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); |
| // Add a sentinal 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. |
| Token *TokenArray = new Token[TokenVector.size()]; |
| std::copy(TokenVector.begin(), TokenVector.end(), TokenArray); |
| auto Value = new (PP.getPreprocessorAllocator()) |
| std::pair<Token*, size_t>(std::make_pair(TokenArray, TokenVector.size())); |
| AnnotTok.setAnnotationValue(Value); |
| PP.EnterToken(AnnotTok); |
| } |
| |
| /// \brief 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, |
| PragmaIntroducerKind Introducer, |
| Token &Tok) { |
| SourceLocation CommentLoc = Tok.getLocation(); |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::l_paren)) { |
| PP.Diag(CommentLoc, 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", |
| /*MacroExpansion=*/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", |
| /*MacroExpansion=*/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(CommentLoc, NameString, |
| ValueString); |
| |
| Actions.ActOnPragmaDetectMismatch(NameString, ValueString); |
| } |
| |
| /// \brief 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, |
| PragmaIntroducerKind 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(); |
| Sema::PragmaMSCommentKind Kind = |
| llvm::StringSwitch<Sema::PragmaMSCommentKind>(II->getName()) |
| .Case("linker", Sema::PCK_Linker) |
| .Case("lib", Sema::PCK_Lib) |
| .Case("compiler", Sema::PCK_Compiler) |
| .Case("exestr", Sema::PCK_ExeStr) |
| .Case("user", Sema::PCK_User) |
| .Default(Sema::PCK_Unknown); |
| if (Kind == Sema::PCK_Unknown) { |
| PP.Diag(Tok.getLocation(), diag::err_pragma_comment_unknown_kind); |
| return; |
| } |
| |
| // Read the optional string if present. |
| PP.Lex(Tok); |
| std::string ArgumentString; |
| if (Tok.is(tok::comma) && !PP.LexStringLiteral(Tok, ArgumentString, |
| "pragma comment", |
| /*MacroExpansion=*/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(Kind, ArgumentString); |
| } |
| |
| // #pragma clang optimize off |
| // #pragma clang optimize on |
| void PragmaOptimizeHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &FirstToken) { |
| Token Tok; |
| PP.Lex(Tok); |
| if (Tok.is(tok::eod)) { |
| PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) |
| << "clang optimize" |
| << "'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()); |
| } |
| |
| /// \brief 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) { |
| ValueInParens = Tok.is(tok::l_paren); |
| if (ValueInParens) { |
| PP.Lex(Tok); |
| if (Tok.is(tok::r_paren)) { |
| // Nothing between the parentheses. |
| std::string PragmaString; |
| if (PragmaName.getIdentifierInfo()->getName() == "loop") { |
| PragmaString = "clang loop "; |
| PragmaString += Option.getIdentifierInfo()->getName(); |
| } else { |
| assert(PragmaName.getIdentifierInfo()->getName() == "unroll" && |
| "Unexpected pragma name"); |
| PragmaString = "unroll"; |
| } |
| PP.Diag(Tok.getLocation(), diag::err_pragma_missing_argument) |
| << PragmaString << "a positive integer value"; |
| return true; |
| } |
| } |
| |
| // FIXME: Value should be stored and parsed as a constant expression. |
| Token Value = Tok; |
| |
| if (ValueInParens) { |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::r_paren)) { |
| PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; |
| return true; |
| } |
| } |
| |
| Info.PragmaName = PragmaName; |
| Info.Option = Option; |
| Info.Value = Value; |
| Info.HasValue = true; |
| return false; |
| } |
| |
| /// \brief 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' '(' loop-hint-keyword ')' |
| /// 'vectorize_width' '(' loop-hint-value ')' |
| /// 'interleave_count' '(' loop-hint-value ')' |
| /// 'unroll_count' '(' loop-hint-value ')' |
| /// |
| /// loop-hint-keyword: |
| /// 'enable' |
| /// 'disable' |
| /// |
| /// 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 try to |
| /// unroll the loop completely, and 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. |
| /// If unroll(enable) and unroll_count are both specified only |
| /// unroll_count takes effect. |
| void PragmaLoopHintHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind 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("vectorize_width", true) |
| .Case("interleave_count", true) |
| .Case("unroll_count", true) |
| .Default(false); |
| if (!OptionValid) { |
| PP.Diag(Tok.getLocation(), diag::err_pragma_loop_invalid_option) |
| << /*MissingOption=*/false << OptionInfo; |
| return; |
| } |
| |
| auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; |
| PP.Lex(Tok); |
| bool ValueInParens; |
| if (ParseLoopHintValue(PP, Tok, PragmaName, Option, ValueInParens, *Info)) |
| return; |
| |
| if (!ValueInParens) { |
| PP.Diag(Info->Value.getLocation(), diag::err_expected) << tok::l_paren; |
| return; |
| } |
| |
| // Generate the loop hint token. |
| Token LoopHintTok; |
| LoopHintTok.startToken(); |
| LoopHintTok.setKind(tok::annot_pragma_loop_hint); |
| LoopHintTok.setLocation(PragmaName.getLocation()); |
| LoopHintTok.setAnnotationValue(static_cast<void *>(Info)); |
| TokenList.push_back(LoopHintTok); |
| |
| // Get next optimization option. |
| PP.Lex(Tok); |
| } |
| |
| if (Tok.isNot(tok::eod)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) |
| << "clang loop"; |
| return; |
| } |
| |
| Token *TokenArray = new Token[TokenList.size()]; |
| std::copy(TokenList.begin(), TokenList.end(), TokenArray); |
| |
| PP.EnterTokenStream(TokenArray, TokenList.size(), |
| /*DisableMacroExpansion=*/false, |
| /*OwnsTokens=*/true); |
| } |
| |
| /// \brief Handle the loop unroll optimization pragmas. |
| /// #pragma unroll |
| /// #pragma unroll unroll-hint-value |
| /// #pragma unroll '(' unroll-hint-value ')' |
| /// |
| /// unroll-hint-value: |
| /// constant-expression |
| /// |
| /// Loop unrolling hints are specified with '#pragma unroll'. '#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. |
| void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, |
| PragmaIntroducerKind Introducer, |
| Token &Tok) { |
| // Incoming token is "unroll" of "#pragma unroll". |
| Token PragmaName = Tok; |
| PP.Lex(Tok); |
| auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; |
| if (Tok.is(tok::eod)) { |
| // Unroll pragma without an argument. |
| Info->PragmaName = PragmaName; |
| Info->Option = PragmaName; |
| Info->HasValue = false; |
| } else { |
| // Unroll pragma with an argument: "#pragma unroll N" or |
| // "#pragma unroll(N)". |
| bool ValueInParens; |
| if (ParseLoopHintValue(PP, Tok, PragmaName, PragmaName, ValueInParens, |
| *Info)) |
| return; |
| |
| // In CUDA, the argument to '#pragma unroll' should not be contained in |
| // parentheses. |
| if (PP.getLangOpts().CUDA && ValueInParens) |
| PP.Diag(Info->Value.getLocation(), |
| diag::warn_pragma_unroll_cuda_value_in_parens); |
| |
| PP.Lex(Tok); |
| if (Tok.isNot(tok::eod)) { |
| PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) |
| << "unroll"; |
| return; |
| } |
| } |
| |
| // Generate the hint token. |
| Token *TokenArray = new Token[1]; |
| TokenArray[0].startToken(); |
| TokenArray[0].setKind(tok::annot_pragma_loop_hint); |
| TokenArray[0].setLocation(PragmaName.getLocation()); |
| TokenArray[0].setAnnotationValue(static_cast<void *>(Info)); |
| PP.EnterTokenStream(TokenArray, 1, /*DisableMacroExpansion=*/false, |
| /*OwnsTokens=*/true); |
| } |