Index: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td @@ -911,6 +911,10 @@ def warn_pragma_pack_malformed : Warning< "expected integer or identifier in '#pragma pack' - ignored">, InGroup; +// - #pragma intrinsic +def warn_pragma_intrinsic_builtin : Warning< + "%0 is not a recognized builtin%select{|; consider including to access non-builtin intrinsics}1">, + InGroup; // - #pragma unused def warn_pragma_unused_expected_var : Warning< "expected '#pragma unused' argument to be a variable name">, Index: cfe/trunk/include/clang/Basic/IdentifierTable.h =================================================================== --- cfe/trunk/include/clang/Basic/IdentifierTable.h +++ cfe/trunk/include/clang/Basic/IdentifierTable.h @@ -205,8 +205,7 @@ /// \brief Return a value indicating whether this is a builtin function. /// - /// 0 is not-built-in. 1 is builtin-for-some-nonprimary-target. - /// 2+ are specific builtin functions. + /// 0 is not-built-in. 1+ are specific builtin functions. unsigned getBuiltinID() const { if (ObjCOrBuiltinID >= tok::NUM_OBJC_KEYWORDS) return ObjCOrBuiltinID - tok::NUM_OBJC_KEYWORDS; Index: cfe/trunk/include/clang/Parse/Parser.h =================================================================== --- cfe/trunk/include/clang/Parse/Parser.h +++ cfe/trunk/include/clang/Parse/Parser.h @@ -172,6 +172,7 @@ std::unique_ptr MSCodeSeg; std::unique_ptr MSSection; std::unique_ptr MSRuntimeChecks; + std::unique_ptr MSIntrinsic; std::unique_ptr OptimizeHandler; std::unique_ptr LoopHintHandler; std::unique_ptr UnrollHintHandler; Index: cfe/trunk/lib/Parse/ParsePragma.cpp =================================================================== --- cfe/trunk/lib/Parse/ParsePragma.cpp +++ cfe/trunk/lib/Parse/ParsePragma.cpp @@ -161,6 +161,12 @@ PragmaMSRuntimeChecksHandler() : EmptyPragmaHandler("runtime_checks") {} }; +struct PragmaMSIntrinsicHandler : public PragmaHandler { + PragmaMSIntrinsicHandler() : PragmaHandler("intrinsic") {} + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &FirstToken) override; +}; + } // end namespace void Parser::initializePragmaHandlers() { @@ -229,6 +235,8 @@ PP.AddPragmaHandler(MSSection.get()); MSRuntimeChecks.reset(new PragmaMSRuntimeChecksHandler()); PP.AddPragmaHandler(MSRuntimeChecks.get()); + MSIntrinsic.reset(new PragmaMSIntrinsicHandler()); + PP.AddPragmaHandler(MSIntrinsic.get()); } OptimizeHandler.reset(new PragmaOptimizeHandler(Actions)); @@ -297,6 +305,8 @@ MSSection.reset(); PP.RemovePragmaHandler(MSRuntimeChecks.get()); MSRuntimeChecks.reset(); + PP.RemovePragmaHandler(MSIntrinsic.get()); + MSIntrinsic.reset(); } PP.RemovePragmaHandler("STDC", FPContractHandler.get()); @@ -2127,3 +2137,53 @@ PP.EnterTokenStream(std::move(TokenArray), 1, /*DisableMacroExpansion=*/false); } + +/// \brief Handle the Microsoft \#pragma intrinsic extension. +/// +/// The syntax is: +/// \code +/// #pragma intrinsic(memset) +/// #pragma intrinsic(strlen, memcpy) +/// \endcode +/// +/// Pragma intrisic tells the compiler to use a builtin version of the +/// function. Clang does it anyway, so the pragma doesn't really do anything. +/// Anyway, we emit a warning if the function specified in \#pragma intrinsic +/// isn't an intrinsic in clang and suggest to include intrin.h. +void PragmaMSIntrinsicHandler::HandlePragma(Preprocessor &PP, + PragmaIntroducerKind Introducer, + Token &Tok) { + PP.Lex(Tok); + + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) + << "intrinsic"; + return; + } + PP.Lex(Tok); + + bool SuggestIntrinH = !PP.isMacroDefined("__INTRIN_H"); + + while (Tok.is(tok::identifier)) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + if (!II->getBuiltinID()) + PP.Diag(Tok.getLocation(), diag::warn_pragma_intrinsic_builtin) + << II << SuggestIntrinH; + + PP.Lex(Tok); + if (Tok.isNot(tok::comma)) + break; + PP.Lex(Tok); + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_rparen) + << "intrinsic"; + return; + } + PP.Lex(Tok); + + if (Tok.isNot(tok::eod)) + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) + << "intrinsic"; +} Index: cfe/trunk/test/Preprocessor/pragma_microsoft.c =================================================================== --- cfe/trunk/test/Preprocessor/pragma_microsoft.c +++ cfe/trunk/test/Preprocessor/pragma_microsoft.c @@ -162,3 +162,19 @@ // Test that runtime_checks is parsed but ignored. #pragma runtime_checks("sc", restore) // no-warning + +// Test pragma intrinsic +#pragma intrinsic(memset) // no-warning +#pragma intrinsic(memcpy, strlen, strlen) // no-warning +#pragma intrinsic() // no-warning +#pragma intrinsic(asdf) // expected-warning {{'asdf' is not a recognized builtin; consider including }} +#pragma intrinsic(main) // expected-warning {{'main' is not a recognized builtin; consider including }} +#pragma intrinsic( // expected-warning {{missing ')' after}} +#pragma intrinsic(int) // expected-warning {{missing ')' after}} +#pragma intrinsic(strcmp) asdf // expected-warning {{extra tokens at end}} + +#define __INTRIN_H // there should be no notes after defining __INTRIN_H +#pragma intrinsic(asdf) // expected-warning-re {{'asdf' is not a recognized builtin{{$}}}} +#pragma intrinsic(memset) // no-warning +#undef __INTRIN_H +#pragma intrinsic(asdf) // expected-warning {{'asdf' is not a recognized builtin; consider including }}