From 3f1ec62a8397062b27f2f849ace22e7c97b248f4 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 7 Sep 2016 16:38:32 +0000 Subject: [PATCH] Parsing MS pragma intrinsic Parse pragma intrinsic, display warning if the function isn't a builtin function in clang and suggest including intrin.h. Patch by Albert Gutowski! Reviewers: aaron.ballman, rnk Subscribers: aaron.ballman, cfe-commits Differential Revision: https://reviews.llvm.org/D23944 llvm-svn: 280825 --- clang/include/clang/Basic/DiagnosticParseKinds.td | 4 ++ clang/include/clang/Basic/IdentifierTable.h | 3 +- clang/include/clang/Parse/Parser.h | 1 + clang/lib/Parse/ParsePragma.cpp | 60 +++++++++++++++++++++++ clang/test/Preprocessor/pragma_microsoft.c | 16 ++++++ 5 files changed, 82 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 5138207..1ee2510 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -911,6 +911,10 @@ def warn_pragma_invalid_action : Warning< 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">, diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index fffb504..f9dec79 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -205,8 +205,7 @@ public: /// \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; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index dae0757..d5d885f 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -172,6 +172,7 @@ class Parser : public CodeCompletionHandler { 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; diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index bff5d11..7ae03af 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -161,6 +161,12 @@ struct PragmaMSRuntimeChecksHandler : public EmptyPragmaHandler { 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 @@ void Parser::initializePragmaHandlers() { 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 @@ void Parser::resetPragmaHandlers() { MSSection.reset(); PP.RemovePragmaHandler(MSRuntimeChecks.get()); MSRuntimeChecks.reset(); + PP.RemovePragmaHandler(MSIntrinsic.get()); + MSIntrinsic.reset(); } PP.RemovePragmaHandler("STDC", FPContractHandler.get()); @@ -2127,3 +2137,53 @@ void PragmaUnrollHintHandler::HandlePragma(Preprocessor &PP, 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"; +} diff --git a/clang/test/Preprocessor/pragma_microsoft.c b/clang/test/Preprocessor/pragma_microsoft.c index 2a9e7ba..31b907a 100644 --- a/clang/test/Preprocessor/pragma_microsoft.c +++ b/clang/test/Preprocessor/pragma_microsoft.c @@ -162,3 +162,19 @@ void g() {} // 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 }} -- 2.7.4