Hi majnemer,
Not for commit.
This tries to share some of the code that parses function style pragmas. I
wasn't happy with the code savings, and it's harder to issue good diagnostics.
Therefore, I'm probably going to skip this, unless anyone has some good ideas
on how to do this better.
http://llvm-reviews.chandlerc.com/D2861
Files:
include/clang/Basic/DiagnosticParseKinds.td
lib/Lex/Pragma.cpp
lib/Lex/Preprocessor.cpp
lib/Parse/ParsePragma.cpp
test/Preprocessor/pragma_microsoft.c
test/SemaCXX/member-pointer-ms.cpp
test/SemaCXX/pragma-vtordisp.cpp
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -781,6 +781,8 @@
InGroup<IgnoredPragmas>;
def warn_pragma_expected_punc : Warning<
"expected ')' or ',' in '#pragma %0'">, InGroup<IgnoredPragmas>;
+def warn_pragma_unexpected_params : Warning<
+ "expected %0 to %1 parameters to '#pragma %2'">, InGroup<IgnoredPragmas>;
// - #pragma options
def warn_pragma_options_expected_align : Warning<
"expected 'align' following '#pragma options' - ignored">,
@@ -791,6 +793,9 @@
def warn_pragma_align_invalid_option : Warning<
"invalid alignment option in '#pragma %select{align|options align}0' - ignored">,
InGroup<IgnoredPragmas>;
+def warn_pragma_expected_id_int_or_str : Warning<
+ "expected identifier, integer, or string in '#pragma %0'">,
+ InGroup<IgnoredPragmas>;
// - #pragma pack
def warn_pragma_invalid_action : Warning<
"unknown action for '#pragma %0' - ignored">,
Index: lib/Lex/Pragma.cpp
===================================================================
--- lib/Lex/Pragma.cpp
+++ lib/Lex/Pragma.cpp
@@ -1042,8 +1042,10 @@
PP.Lex(Tok);
uint64_t Value;
if (Tok.is(tok::numeric_constant) &&
- PP.parseSimpleIntegerLiteral(Tok, Value))
+ PP.parseSimpleIntegerLiteral(Tok, Value)) {
Level = int(Value);
+ PP.Lex(Tok);
+ }
if (Level < 0 || Level > 4) {
PP.Diag(Tok, diag::warn_pragma_warning_push_level);
return;
@@ -1093,6 +1095,7 @@
PP.Diag(Tok, diag::warn_pragma_warning_expected_number);
return;
}
+ PP.Lex(Tok);
Ids.push_back(int(Value));
}
if (Callbacks)
Index: lib/Lex/Preprocessor.cpp
===================================================================
--- lib/Lex/Preprocessor.cpp
+++ lib/Lex/Preprocessor.cpp
@@ -790,7 +790,6 @@
llvm::APInt APVal(64, 0);
if (Literal.GetIntegerValue(APVal))
return false;
- Lex(Tok);
Value = APVal.getLimitedValue();
return true;
}
Index: lib/Parse/ParsePragma.cpp
===================================================================
--- lib/Parse/ParsePragma.cpp
+++ lib/Parse/ParsePragma.cpp
@@ -1017,6 +1017,75 @@
/*DisableMacroExpansion=*/true, /*OwnsTokens=*/true);
}
+/// \brief Parses function-style pragmas with macro expansion, which MSVC uses
+/// exclusively. Produces a list of comma separated tokens.
+///
+/// <function-pragma> ::= 'PragmaName' '(' [ <function-arg> ( ',' <function-arg> )+ ] ')'
+/// <function-arg> ::= identifier | string-literal+ | numeric-literal
+static bool parseMSVCFunctionStylePragma(Preprocessor &PP,
+ const char *PragmaName, Token &Tok,
+ SmallVectorImpl<Token> &Args) {
+ assert(Tok.getIdentifierInfo() &&
+ Tok.getIdentifierInfo()->getName() == StringRef(PragmaName));
+ PP.Lex(Tok);
+
+ if (Tok.isNot(tok::l_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_lparen) << PragmaName;
+ return false;
+ }
+
+ PP.Lex(Tok);
+ while (Tok.isNot(tok::r_paren)) {
+ // <function-arg> ::= identifier | string-literal+ | numeric-literal
+ switch (Tok.getKind()) {
+ case tok::identifier:
+ case tok::numeric_constant:
+ Args.push_back(Tok);
+ PP.Lex(Tok);
+ break;
+ case tok::string_literal: {
+ // MSVC rejects other string literals here.
+ SmallString<20> DiagnosticTag("pragma ");
+ DiagnosticTag += PragmaName; // FIXME: Is this a UAF situation?
+ std::string Str;
+ SourceLocation StartLoc = Tok.getLocation();
+ PP.EnterToken(Tok); // Push back the first string literal we lexed.
+ if (!PP.LexStringLiteral(Tok, Str, DiagnosticTag.c_str(),
+ /*MacroExpansion=*/true))
+ return false;
+ // Create an artificial string token for the concatenated result.
+ Token StrTok;
+ StrTok.startToken();
+ StrTok.setKind(tok::string_literal);
+ PP.CreateString(Str, StrTok, StartLoc, Tok.getLocation());
+ Args.push_back(StrTok);
+ break;
+ }
+ default:
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_id_int_or_str)
+ << PragmaName;
+ return false;
+ }
+
+ // ',' or ')'
+ if (Tok.is(tok::comma)) {
+ PP.Lex(Tok);
+ } else if (Tok.isNot(tok::r_paren)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_punc) << PragmaName;
+ return false;
+ }
+ }
+ PP.Lex(Tok); // Eat the r_paren.
+
+ if (Tok.isNot(tok::eod)) {
+ PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
+ << PragmaName;
+ return false;
+ }
+
+ return true;
+}
+
/// \brief Handle '#pragma pointers_to_members'
// The grammar for this pragma is as follows:
//
@@ -1029,78 +1098,53 @@
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";
+ SmallVector<Token, 2> Args;
+ if (!parseMSVCFunctionStylePragma(PP, "pointers_to_members", Tok, Args))
return;
- }
- PP.Lex(Tok);
- const IdentifierInfo *Arg = Tok.getIdentifierInfo();
- if (!Arg) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier)
- << "pointers_to_members";
+
+ if (Args.size() == 0 || Args.size() > 2) {
+ PP.Diag(PointersToMembersLoc, diag::warn_pragma_unexpected_params)
+ << 1 << 2 << "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 = 0;
- 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 there are two args, the first has to be 'full_generality'.
+ if (Args.size() == 2) {
+ Token Arg = Args.front();
+ const IdentifierInfo *II = Arg.getIdentifierInfo();
+ if (!II || !II->isStr("full_generality")) {
+ // FIXME: Less confusing error message?
+ PP.Diag(Arg.getLocation(),
+ diag::err_pragma_pointers_to_members_unknown_kind)
+ << Arg.getKind() << /*HasPointerDeclaration*/ 1;
+ return;
}
}
- if (Tok.isNot(tok::r_paren)) {
- PP.Diag(Tok.getLocation(), diag::err_expected_rparen_after)
- << (Arg ? Arg->getName() : "full_generality");
- return;
+ // #pragma pointers_to_members(full_generality) implicitly specifies
+ // virtual_inheritance.
+ // 'best_case' | 'full_generality' | inheritance-model
+ Token Arg = Args.back();
+ const IdentifierInfo *II = Arg.getIdentifierInfo();
+ unsigned RepresentationMethod = ~0U;
+ if (II) {
+ RepresentationMethod =
+ llvm::StringSwitch<unsigned>(II->getName())
+ .Case("best_case", LangOptions::PPTMK_BestCase)
+ .Case("single_inheritance",
+ LangOptions::PPTMK_FullGeneralitySingleInheritance)
+ .Case("multiple_inheritance",
+ LangOptions::PPTMK_FullGeneralityMultipleInheritance)
+ .Case("virtual_inheritance",
+ LangOptions::PPTMK_FullGeneralityVirtualInheritance)
+ .Case("full_generality",
+ LangOptions::PPTMK_FullGeneralityVirtualInheritance)
+ .Default(~0U);
}
-
- PP.Lex(Tok);
- if (Tok.isNot(tok::eod)) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol)
- << "pointers_to_members";
+ if (RepresentationMethod == ~0) {
+ PP.Diag(Arg.getLocation(),
+ diag::err_pragma_pointers_to_members_unknown_kind)
+ << Arg.getKind() << /*HasPointerDeclaration*/ 0;
return;
}
@@ -1125,53 +1169,45 @@
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";
+ SmallVector<Token, 2> Args;
+ if (!parseMSVCFunctionStylePragma(PP, "vtordisp", Tok, Args))
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
+ unsigned ExpectedArgs = 1;
+ if (Args.size() == 0) {
+ Kind = Sema::PVDK_Reset;
+ ExpectedArgs = 0;
} else {
- if (Tok.is(tok::r_paren)) {
- // #pragma vtordisp()
- Kind = Sema::PVDK_Reset;
+ const IdentifierInfo *II = Args[0].getIdentifierInfo();
+ if (II) {
+ if (II->isStr("push")) {
+ Kind = Sema::PVDK_Push;
+ ExpectedArgs = 2;
+ } else if (II->isStr("pop")) {
+ Kind = Sema::PVDK_Pop;
+ }
}
}
+ if (Args.size() != ExpectedArgs) {
+ PP.Diag(VtorDispLoc, diag::warn_pragma_unexpected_params)
+ << ExpectedArgs << ExpectedArgs << "vtordisp";
+ return;
+ }
uint64_t Value = 0;
if (Kind == Sema::PVDK_Push || Kind == Sema::PVDK_Set) {
- const IdentifierInfo *II = Tok.getIdentifierInfo();
+ Token &Arg = Args.back();
+ const IdentifierInfo *II = Arg.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)) {
+ } else if (Arg.is(tok::numeric_constant) &&
+ PP.parseSimpleIntegerLiteral(Arg, Value)) {
if (Value > 2) {
- PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_integer)
+ PP.Diag(Arg.getLocation(), diag::warn_pragma_expected_integer)
<< 0 << 2 << "vtordisp";
return;
}
@@ -1182,18 +1218,6 @@
}
}
- // 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();
@@ -1217,48 +1241,24 @@
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))
+ SourceLocation PragmaLoc = Tok.getLocation();
+ SmallVector<Token, 2> Args;
+ if (!parseMSVCFunctionStylePragma(PP, "detect_mismatch", Tok, Args))
return;
-
- // Read the comma followed by a second string literal.
- std::string ValueString;
- if (Tok.isNot(tok::comma)) {
+ if (Args.size() != 2)
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;
+ else if (Args[0].isNot(tok::string_literal))
+ PP.Diag(Args[0].getLocation(), diag::err_pragma_detect_mismatch_malformed);
+ else if (Args[1].isNot(tok::string_literal))
+ PP.Diag(Args[1].getLocation(), diag::err_pragma_detect_mismatch_malformed);
+ else {
+ // If the pragma is lexically sound, notify any interested PPCallbacks.
+ const char *NameStr = Args[0].getLiteralData();
+ const char *ValStr = Args[1].getLiteralData();
+ if (PP.getPPCallbacks())
+ PP.getPPCallbacks()->PragmaDetectMismatch(PragmaLoc, NameStr, ValStr);
+ Actions.ActOnPragmaDetectMismatch(NameStr, ValStr);
}
-
- // 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.
Index: test/Preprocessor/pragma_microsoft.c
===================================================================
--- test/Preprocessor/pragma_microsoft.c
+++ test/Preprocessor/pragma_microsoft.c
@@ -19,9 +19,9 @@
#pragma comment(user, "foo\abar\nbaz\tsome thing")
#pragma detect_mismatch("test", "1")
-#pragma detect_mismatch() // expected-error {{expected string literal in pragma detect_mismatch}}
-#pragma detect_mismatch("test") // expected-error {{pragma detect_mismatch is malformed; it requires two comma-separated string literals}}
-#pragma detect_mismatch("test", 1) // expected-error {{expected string literal in pragma detect_mismatch}}
+#pragma detect_mismatch() // expected-error {{pragma detect_mismatch is malformed}}
+#pragma detect_mismatch("test") // expected-error {{pragma detect_mismatch is malformed}}
+#pragma detect_mismatch("test", 1) // expected-error {{pragma detect_mismatch is malformed}}
#pragma detect_mismatch("test", BAR)
// __pragma
Index: test/SemaCXX/member-pointer-ms.cpp
===================================================================
--- test/SemaCXX/member-pointer-ms.cpp
+++ test/SemaCXX/member-pointer-ms.cpp
@@ -270,5 +270,5 @@
#pragma pointers_to_members(virtual_inheritance)
static_assert(sizeof(int SingleInheritanceAsVirtualBeforePragma::*) == 12, "");
-#pragma pointers_to_members(single) // expected-error{{unexpected 'single'}}
+#pragma pointers_to_members(single) // expected-error{{unexpected identifier}}
#endif
Index: test/SemaCXX/pragma-vtordisp.cpp
===================================================================
--- test/SemaCXX/pragma-vtordisp.cpp
+++ test/SemaCXX/pragma-vtordisp.cpp
@@ -24,9 +24,9 @@
#pragma vtordisp()
#pragma vtordisp(pop) // expected-warning {{#pragma vtordisp(pop, ...) failed: stack empty}}
-#pragma vtordisp( // expected-warning {{unknown action for '#pragma vtordisp' - ignored}}
+#pragma vtordisp( // expected-warning {{expected identifier, integer, or string}}
#pragma vtordisp(asdf) // expected-warning {{unknown action for '#pragma vtordisp' - ignored}}
-#pragma vtordisp(,) // expected-warning {{unknown action for '#pragma vtordisp' - ignored}}
+#pragma vtordisp(,) // expected-warning {{expected identifier, integer, or string}}
#pragma vtordisp // expected-warning {{missing '(' after '#pragma vtordisp' - ignoring}}
#pragma vtordisp(3) // expected-warning {{expected integer between 0 and 2 inclusive in '#pragma vtordisp' - ignored}}
#pragma vtordisp(), stuff // expected-warning {{extra tokens}}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits