Skip to content

Commit

Permalink
Add PragmaHandler for MSVC pragma execution_character_set
Browse files Browse the repository at this point in the history
__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

llvm-svn: 356185
  • Loading branch information
rnk committed Mar 14, 2019
1 parent 81abc7f commit 0f56b22
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 0 deletions.
16 changes: 16 additions & 0 deletions clang-tools-extra/pp-trace/PPCallbacksTracker.cpp
Expand Up @@ -297,6 +297,22 @@ void PPCallbacksTracker::PragmaWarningPop(clang::SourceLocation Loc) {
appendArgument("Loc", Loc);
}

// Callback invoked when a #pragma execution_character_set(push) directive
// is read.
void PPCallbacksTracker::PragmaExecCharsetPush(clang::SourceLocation Loc,
clang::StringRef Str) {
beginCallback("PragmaExecCharsetPush");
appendArgument("Loc", Loc);
appendArgument("Charset", Str);
}

// Callback invoked when a #pragma execution_character_set(pop) directive
// is read.
void PPCallbacksTracker::PragmaExecCharsetPop(clang::SourceLocation Loc) {
beginCallback("PragmaExecCharsetPop");
appendArgument("Loc", Loc);
}

// Called by Preprocessor::HandleMacroExpandedIdentifier when a
// macro invocation is found.
void
Expand Down
3 changes: 3 additions & 0 deletions clang-tools-extra/pp-trace/PPCallbacksTracker.h
Expand Up @@ -134,6 +134,9 @@ class PPCallbacksTracker : public clang::PPCallbacks {
llvm::ArrayRef<int> Ids) override;
void PragmaWarningPush(clang::SourceLocation Loc, int Level) override;
void PragmaWarningPop(clang::SourceLocation Loc) override;
void PragmaExecCharsetPush(clang::SourceLocation Loc,
clang::StringRef Str) override;
void PragmaExecCharsetPop(clang::SourceLocation Loc) override;
void MacroExpands(const clang::Token &MacroNameTok,
const clang::MacroDefinition &MD, clang::SourceRange Range,
const clang::MacroArgs *Args) override;
Expand Down
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/DiagnosticLexKinds.td
Expand Up @@ -506,6 +506,17 @@ def warn_pragma_warning_expected_number :
ExtWarn<"#pragma warning expected a warning number">,
InGroup<UnknownPragmas>;

// - #pragma execution_character_set(...)
def warn_pragma_exec_charset_expected :
ExtWarn<"#pragma execution_character_set expected '%0'">,
InGroup<UnknownPragmas>;
def warn_pragma_exec_charset_spec_invalid :
ExtWarn<"#pragma execution_character_set expected 'push' or 'pop'">,
InGroup<UnknownPragmas>;
def warn_pragma_exec_charset_push_invalid :
ExtWarn<"#pragma execution_character_set invalid value '%0', only 'UTF-8' is supported">,
InGroup<UnknownPragmas>;

def err__Pragma_malformed : Error<
"_Pragma takes a parenthesized string literal">;
def err_pragma_message_malformed : Error<
Expand Down
18 changes: 18 additions & 0 deletions clang/include/clang/Lex/PPCallbacks.h
Expand Up @@ -239,6 +239,14 @@ class PPCallbacks {
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) {}
Expand Down Expand Up @@ -477,6 +485,16 @@ class PPChainedCallbacks : public PPCallbacks {
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);
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Frontend/PrintPreprocessedOutput.cpp
Expand Up @@ -143,6 +143,8 @@ class PrintPPOutputPPCallbacks : public PPCallbacks {
ArrayRef<int> 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;

Expand Down Expand Up @@ -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();
Expand Down
65 changes: 65 additions & 0 deletions clang/lib/Lex/Pragma.cpp
Expand Up @@ -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") {}
Expand Down Expand Up @@ -1823,6 +1887,7 @@ void Preprocessor::RegisterBuiltinPragmas() {
// MS extensions.
if (LangOpts.MicrosoftExt) {
AddPragmaHandler(new PragmaWarningHandler());
AddPragmaHandler(new PragmaExecCharsetHandler());
AddPragmaHandler(new PragmaIncludeAliasHandler());
AddPragmaHandler(new PragmaHdrstopHandler());
}
Expand Down
18 changes: 18 additions & 0 deletions clang/test/Preprocessor/pragma_microsoft.c
Expand Up @@ -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)

0 comments on commit 0f56b22

Please sign in to comment.