From: Reid Kleckner Date: Thu, 14 Mar 2019 18:12:17 +0000 (+0000) Subject: Add PragmaHandler for MSVC pragma execution_character_set X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d2d8393da1878076623325a0f5102fc9dec3e10a;p=clang Add PragmaHandler for MSVC pragma execution_character_set __pragma(execution_character_set(push, "UTF-8")) is used in TraceLoggingProvider.h. This commit implements a no-op handler for compatability, similar to how the flag -fexec_charset is handled. Patch by Matt Gardner! Differential Revision: https://reviews.llvm.org/D58530 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@356185 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticLexKinds.td b/include/clang/Basic/DiagnosticLexKinds.td index da73e62c9d..45e50c9a8c 100644 --- a/include/clang/Basic/DiagnosticLexKinds.td +++ b/include/clang/Basic/DiagnosticLexKinds.td @@ -506,6 +506,17 @@ def warn_pragma_warning_expected_number : ExtWarn<"#pragma warning expected a warning number">, InGroup; +// - #pragma execution_character_set(...) +def warn_pragma_exec_charset_expected : + ExtWarn<"#pragma execution_character_set expected '%0'">, + InGroup; +def warn_pragma_exec_charset_spec_invalid : + ExtWarn<"#pragma execution_character_set expected 'push' or 'pop'">, + InGroup; +def warn_pragma_exec_charset_push_invalid : + ExtWarn<"#pragma execution_character_set invalid value '%0', only 'UTF-8' is supported">, + InGroup; + def err__Pragma_malformed : Error< "_Pragma takes a parenthesized string literal">; def err_pragma_message_malformed : Error< diff --git a/include/clang/Lex/PPCallbacks.h b/include/clang/Lex/PPCallbacks.h index 92943bdd01..33f3c804db 100644 --- a/include/clang/Lex/PPCallbacks.h +++ b/include/clang/Lex/PPCallbacks.h @@ -239,6 +239,14 @@ public: virtual void PragmaWarningPop(SourceLocation Loc) { } + /// Callback invoked when a \#pragma execution_character_set(push) directive + /// is read. + virtual void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) {} + + /// Callback invoked when a \#pragma execution_character_set(pop) directive + /// is read. + virtual void PragmaExecCharsetPop(SourceLocation Loc) {} + /// Callback invoked when a \#pragma clang assume_nonnull begin directive /// is read. virtual void PragmaAssumeNonNullBegin(SourceLocation Loc) {} @@ -477,6 +485,16 @@ public: Second->PragmaWarningPop(Loc); } + void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override { + First->PragmaExecCharsetPush(Loc, Str); + Second->PragmaExecCharsetPush(Loc, Str); + } + + void PragmaExecCharsetPop(SourceLocation Loc) override { + First->PragmaExecCharsetPop(Loc); + Second->PragmaExecCharsetPop(Loc); + } + void PragmaAssumeNonNullBegin(SourceLocation Loc) override { First->PragmaAssumeNonNullBegin(Loc); Second->PragmaAssumeNonNullBegin(Loc); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 490830c524..e8162ec95f 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -143,6 +143,8 @@ public: ArrayRef Ids) override; void PragmaWarningPush(SourceLocation Loc, int Level) override; void PragmaWarningPop(SourceLocation Loc) override; + void PragmaExecCharsetPush(SourceLocation Loc, StringRef Str) override; + void PragmaExecCharsetPop(SourceLocation Loc) override; void PragmaAssumeNonNullBegin(SourceLocation Loc) override; void PragmaAssumeNonNullEnd(SourceLocation Loc) override; @@ -553,6 +555,24 @@ void PrintPPOutputPPCallbacks::PragmaWarningPop(SourceLocation Loc) { setEmittedDirectiveOnThisLine(); } +void PrintPPOutputPPCallbacks::PragmaExecCharsetPush(SourceLocation Loc, + StringRef Str) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma character_execution_set(push"; + if (!Str.empty()) + OS << ", " << Str; + OS << ')'; + setEmittedDirectiveOnThisLine(); +} + +void PrintPPOutputPPCallbacks::PragmaExecCharsetPop(SourceLocation Loc) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma character_execution_set(pop)"; + setEmittedDirectiveOnThisLine(); +} + void PrintPPOutputPPCallbacks:: PragmaAssumeNonNullBegin(SourceLocation Loc) { startNewLineIfNeeded(); diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index c82b531737..5564c0c40a 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -1368,6 +1368,70 @@ struct PragmaWarningHandler : public PragmaHandler { } }; +/// "\#pragma execution_character_set(...)". MSVC supports this pragma only +/// for "UTF-8". We parse it and ignore it if UTF-8 is provided and warn +/// otherwise to avoid -Wunknown-pragma warnings. +struct PragmaExecCharsetHandler : public PragmaHandler { + PragmaExecCharsetHandler() : PragmaHandler("execution_character_set") {} + + void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, + Token &Tok) override { + // Parse things like: + // execution_character_set(push, "UTF-8") + // execution_character_set(pop) + SourceLocation DiagLoc = Tok.getLocation(); + PPCallbacks *Callbacks = PP.getPPCallbacks(); + + PP.Lex(Tok); + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok, diag::warn_pragma_exec_charset_expected) << "("; + return; + } + + PP.Lex(Tok); + IdentifierInfo *II = Tok.getIdentifierInfo(); + + if (II && II->isStr("push")) { + // #pragma execution_character_set( push[ , string ] ) + PP.Lex(Tok); + if (Tok.is(tok::comma)) { + PP.Lex(Tok); + + std::string ExecCharset; + if (!PP.FinishLexStringLiteral(Tok, ExecCharset, + "pragma execution_character_set", + /*MacroExpansion=*/false)) + return; + + // MSVC supports either of these, but nothing else. + if (ExecCharset != "UTF-8" && ExecCharset != "utf-8") { + PP.Diag(Tok, diag::warn_pragma_exec_charset_push_invalid) << ExecCharset; + return; + } + } + if (Callbacks) + Callbacks->PragmaExecCharsetPush(DiagLoc, "UTF-8"); + } else if (II && II->isStr("pop")) { + // #pragma execution_character_set( pop ) + PP.Lex(Tok); + if (Callbacks) + Callbacks->PragmaExecCharsetPop(DiagLoc); + } else { + PP.Diag(Tok, diag::warn_pragma_exec_charset_spec_invalid); + return; + } + + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok, diag::warn_pragma_exec_charset_expected) << ")"; + return; + } + + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) + PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma execution_character_set"; + } +}; + /// PragmaIncludeAliasHandler - "\#pragma include_alias("...")". struct PragmaIncludeAliasHandler : public PragmaHandler { PragmaIncludeAliasHandler() : PragmaHandler("include_alias") {} @@ -1823,6 +1887,7 @@ void Preprocessor::RegisterBuiltinPragmas() { // MS extensions. if (LangOpts.MicrosoftExt) { AddPragmaHandler(new PragmaWarningHandler()); + AddPragmaHandler(new PragmaExecCharsetHandler()); AddPragmaHandler(new PragmaIncludeAliasHandler()); AddPragmaHandler(new PragmaHdrstopHandler()); } diff --git a/test/Preprocessor/pragma_microsoft.c b/test/Preprocessor/pragma_microsoft.c index 4105e41af4..0e1f1dbd1c 100644 --- a/test/Preprocessor/pragma_microsoft.c +++ b/test/Preprocessor/pragma_microsoft.c @@ -198,3 +198,21 @@ void g() {} #pragma optimize("g", // expected-warning{{missing argument to '#pragma optimize'; expected 'on' or 'off'}} #pragma optimize("g",xyz // expected-warning{{unexpected argument 'xyz' to '#pragma optimize'; expected 'on' or 'off'}} #pragma optimize("g",on) // expected-warning{{#pragma optimize' is not supported}} + +#pragma execution_character_set // expected-warning {{expected '('}} +#pragma execution_character_set( // expected-warning {{expected 'push' or 'pop'}} +#pragma execution_character_set() // expected-warning {{expected 'push' or 'pop'}} +#pragma execution_character_set(asdf // expected-warning {{expected 'push' or 'pop'}} +#pragma execution_character_set(asdf) // expected-warning {{expected 'push' or 'pop'}} +#pragma execution_character_set(push // expected-warning {{expected ')'}} +#pragma execution_character_set(pop,) // expected-warning {{expected ')'}} +#pragma execution_character_set(pop,"asdf") // expected-warning {{expected ')'}} +#pragma execution_character_set(push, // expected-error {{expected string literal}} +#pragma execution_character_set(push,) // expected-error {{expected string literal}} +#pragma execution_character_set(push,asdf) // expected-error {{expected string literal}} +#pragma execution_character_set(push, "asdf") // expected-warning {{only 'UTF-8' is supported}} + +#pragma execution_character_set(push) +#pragma execution_character_set(push, "utf-8") +#pragma execution_character_set(push, "UTF-8") +#pragma execution_character_set(pop) \ No newline at end of file