diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp | 1062 |
1 files changed, 1048 insertions, 14 deletions
diff --git a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp index 8a374e0..d3777f3 100644 --- a/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp +++ b/contrib/llvm/tools/clang/lib/Parse/ParsePragma.cpp @@ -11,14 +11,288 @@ // //===----------------------------------------------------------------------===// -#include "ParsePragma.h" +#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. @@ -130,7 +404,7 @@ StmtResult Parser::HandlePragmaCaptured() ConsumeToken(); if (Tok.isNot(tok::l_brace)) { - PP.Diag(Tok, diag::err_expected_lbrace); + PP.Diag(Tok, diag::err_expected) << tok::l_brace; return StmtError(); } @@ -180,7 +454,307 @@ void Parser::HandlePragmaOpenCLExtension() { } } +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] ')' @@ -197,7 +771,7 @@ void PragmaGCCVisibilityHandler::HandlePragma(Preprocessor &PP, const IdentifierInfo *VisType; if (PushPop && PushPop->isStr("pop")) { - VisType = 0; + VisType = nullptr; } else if (PushPop && PushPop->isStr("push")) { PP.LexUnexpandedToken(Tok); if (Tok.isNot(tok::l_paren)) { @@ -257,7 +831,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, } Sema::PragmaPackKind Kind = Sema::PPK_Default; - IdentifierInfo *Name = 0; + IdentifierInfo *Name = nullptr; Token Alignment; Alignment.startToken(); SourceLocation LParenLoc = Tok.getLocation(); @@ -283,7 +857,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, } else if (II->isStr("pop")) { Kind = Sema::PPK_Pop; } else { - PP.Diag(Tok.getLocation(), diag::warn_pragma_pack_invalid_action); + PP.Diag(Tok.getLocation(), diag::warn_pragma_invalid_action) << "pack"; return; } PP.Lex(Tok); @@ -530,7 +1104,7 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, } // Illegal token! - PP.Diag(Tok.getLocation(), diag::warn_pragma_unused_expected_punc); + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_punc) << "unused"; return; } @@ -760,13 +1334,11 @@ void PragmaNoOpenMPHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstTok) { - if (PP.getDiagnostics().getDiagnosticLevel(diag::warn_pragma_omp_ignored, - FirstTok.getLocation()) != - DiagnosticsEngine::Ignored) { + if (!PP.getDiagnostics().isIgnored(diag::warn_pragma_omp_ignored, + FirstTok.getLocation())) { PP.Diag(FirstTok, diag::warn_pragma_omp_ignored); - PP.getDiagnostics().setDiagnosticMapping(diag::warn_pragma_omp_ignored, - diag::MAP_IGNORE, - SourceLocation()); + PP.getDiagnostics().setSeverity(diag::warn_pragma_omp_ignored, + diag::Severity::Ignored, SourceLocation()); } PP.DiscardUntilEndOfDirective(); } @@ -799,6 +1371,220 @@ PragmaOpenMPHandler::HandlePragma(Preprocessor &PP, /*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: @@ -815,7 +1601,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, SourceLocation CommentLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::l_paren)) { - PP.Diag(CommentLoc, diag::err_expected_lparen); + PP.Diag(CommentLoc, diag::err_expected) << tok::l_paren; return; } @@ -838,7 +1624,7 @@ void PragmaDetectMismatchHandler::HandlePragma(Preprocessor &PP, return; if (Tok.isNot(tok::r_paren)) { - PP.Diag(Tok.getLocation(), diag::err_expected_rparen); + PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; return; } PP.Lex(Tok); // Eat the r_paren. @@ -929,3 +1715,251 @@ void PragmaCommentHandler::HandlePragma(Preprocessor &PP, 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); +} |