//===--- 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/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; }; } // 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()); } 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(); } /// \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(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(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( reinterpret_cast(Tok.getAnnotationValue())); Actions.ActOnPragmaMSStruct(Kind); ConsumeToken(); // The annotation token. } void Parser::HandlePragmaAlign() { assert(Tok.is(tok::annot_pragma_align)); Sema::PragmaOptionsAlignKind Kind = static_cast( reinterpret_cast(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( reinterpret_cast(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 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( reinterpret_cast(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(Tok.getAnnotationValue()); Sema::PragmaVtorDispKind Kind = static_cast((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 *)Tok.getAnnotationValue(); PP.EnterTokenStream(TheTokens->first, TheTokens->second, true, true); SourceLocation PragmaLocation = ConsumeToken(); // The annotation token. assert(Tok.isAnyIdentifier()); llvm::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 unsigned (Parser::*PragmaHandler)(llvm::StringRef, SourceLocation); PragmaHandler Handler = llvm::StringSwitch(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 (auto DiagID = (this->*Handler)(PragmaName, PragmaLocation)) { PP.Diag(PragmaLocation, DiagID) << PragmaName; while (Tok.isNot(tok::eof)) PP.Lex(Tok); PP.Lex(Tok); } } unsigned Parser::HandlePragmaMSSection(llvm::StringRef PragmaName, SourceLocation PragmaLocation) { if (Tok.isNot(tok::l_paren)) return diag::warn_pragma_expected_lparen; PP.Lex(Tok); // ( // Parsing code for pragma section if (Tok.isNot(tok::string_literal)) return diag::warn_pragma_expected_section_name; StringLiteral *SegmentName = cast(ParseStringLiteralExpression().get()); int SectionFlags = 0; while (Tok.is(tok::comma)) { PP.Lex(Tok); // , if (!Tok.isAnyIdentifier()) return diag::warn_pragma_expected_action_or_r_paren; Sema::PragmaSectionFlag Flag = llvm::StringSwitch( 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(); while (Tok.isNot(tok::eof)) PP.Lex(Tok); PP.Lex(Tok); return 0; } SectionFlags |= Flag; PP.Lex(Tok); // Identifier } if (Tok.isNot(tok::r_paren)) return diag::warn_pragma_expected_rparen; PP.Lex(Tok); // ) if (Tok.isNot(tok::eof)) return diag::warn_pragma_extra_tokens_at_eol; PP.Lex(Tok); // eof Actions.ActOnPragmaMSSection(PragmaLocation, SectionFlags, SegmentName); return 0; } unsigned Parser::HandlePragmaMSSegment(llvm::StringRef PragmaName, SourceLocation PragmaLocation) { if (Tok.isNot(tok::l_paren)) return diag::warn_pragma_expected_lparen; PP.Lex(Tok); // ( Sema::PragmaMsStackAction Action = Sema::PSK_Reset; llvm::StringRef SlotLabel; if (Tok.isAnyIdentifier()) { llvm::StringRef PushPop = Tok.getIdentifierInfo()->getName(); if (PushPop == "push") Action = Sema::PSK_Push; else if (PushPop == "pop") Action = Sema::PSK_Pop; else return diag::warn_pragma_expected_section_push_pop_or_name; 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)) return diag::warn_pragma_expected_punc; } } else if (Tok.isNot(tok::r_paren)) return diag::warn_pragma_expected_punc; } } // Grab the string literal for our section name. StringLiteral *SegmentName = nullptr; if (Tok.isNot(tok::r_paren)) { if (Tok.isNot(tok::string_literal)) return 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; SegmentName = cast(ParseStringLiteralExpression().get()); // Setting section "" has no effect if (SegmentName->getLength()) Action = (Sema::PragmaMsStackAction)(Action | Sema::PSK_Set); } if (Tok.isNot(tok::r_paren)) return diag::warn_pragma_expected_rparen; PP.Lex(Tok); // ) if (Tok.isNot(tok::eof)) return diag::warn_pragma_extra_tokens_at_eol; PP.Lex(Tok); // eof Actions.ActOnPragmaMSSeg(PragmaLocation, Action, SlotLabel, SegmentName, PragmaName); return 0; } unsigned Parser::HandlePragmaMSInitSeg(llvm::StringRef PragmaName, SourceLocation PragmaLocation) { return PP.getDiagnostics().getCustomDiagID( DiagnosticsEngine::Error, "'#pragma %0' not implemented."); } struct PragmaLoopHintInfo { Token Loop; Token Value; Token Option; }; LoopHint Parser::HandlePragmaLoopHint() { assert(Tok.is(tok::annot_pragma_loop_hint)); PragmaLoopHintInfo *Info = static_cast(Tok.getAnnotationValue()); LoopHint Hint; Hint.LoopLoc = IdentifierLoc::create(Actions.Context, Info->Loop.getLocation(), Info->Loop.getIdentifierInfo()); Hint.OptionLoc = IdentifierLoc::create(Actions.Context, Info->Option.getLocation(), Info->Option.getIdentifierInfo()); Hint.ValueLoc = IdentifierLoc::create(Actions.Context, Info->Value.getLocation(), Info->Value.getIdentifierInfo()); Hint.Range = SourceRange(Info->Option.getLocation(), Info->Value.getLocation()); // 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; 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(static_cast(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()); 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()); new (Toks) Token(); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_pack); Toks[0].setLocation(PackLoc); Toks[0].setAnnotationValue(static_cast(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()); new (Toks) Token(); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_msstruct); Toks[0].setLocation(MSStructTok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast( static_cast(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()); new (Toks) Token(); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_align); Toks[0].setLocation(FirstTok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast( static_cast(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 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()); 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 &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 &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 &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()); new (Toks) Token(); Toks[0].startToken(); Toks[0].setKind(tok::annot_pragma_fp_contract); Toks[0].setLocation(Tok.getLocation()); Toks[0].setAnnotationValue(reinterpret_cast( static_cast(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()); 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 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: // // ::= ('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(static_cast(RepresentationMethod))); PP.EnterToken(AnnotTok); } /// \brief Handle '#pragma vtordisp' // The grammar for this pragma is as follows: // // ::= ('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( static_cast((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 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(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(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_optimize_missing_argument); 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 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) { Token Loop = Tok; SmallVector 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(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; } // Read '(' PP.Lex(Tok); if (Tok.isNot(tok::l_paren)) { PP.Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; return; } // FIXME: All tokens between '(' and ')' should be stored and parsed as a // constant expression. PP.Lex(Tok); if (Tok.is(tok::r_paren)) { // Nothing between the parentheses. PP.Diag(Tok.getLocation(), diag::err_pragma_loop_missing_argument) << OptionInfo; return; } Token Value = Tok; // Read ')' PP.Lex(Tok); if (Tok.isNot(tok::r_paren)) { PP.Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; return; } // Get next optimization option. PP.Lex(Tok); auto *Info = new (PP.getPreprocessorAllocator()) PragmaLoopHintInfo; Info->Loop = Loop; Info->Option = Option; Info->Value = Value; // Generate the vectorization hint token. Token LoopHintTok; LoopHintTok.startToken(); LoopHintTok.setKind(tok::annot_pragma_loop_hint); LoopHintTok.setLocation(Loop.getLocation()); LoopHintTok.setAnnotationValue(static_cast(Info)); TokenList.push_back(LoopHintTok); } 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); }