Repository navigation
[Clang] Support libstdc++ workarounds when using -E
#210802
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e8d94c9
2758463
6bdc1c9
185353f
3181728
b3a359d
fde278d
46b9a02
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,10 +29,12 @@ | |
| using namespace clang; | ||
|
|
||
| /// PrintMacroDefinition - Print a macro definition in a form that will be | ||
| /// properly accepted back as a definition. | ||
| static void PrintMacroDefinition(const IdentifierInfo &II, const MacroInfo &MI, | ||
| /// properly accepted back as a definition. If 'II' is nullptr, only the | ||
| /// expansion will be printed. | ||
| static void PrintMacroDefinition(const IdentifierInfo *II, const MacroInfo &MI, | ||
| Preprocessor &PP, raw_ostream *OS) { | ||
| *OS << "#define " << II.getName(); | ||
| if (II) | ||
| *OS << "#define " << II->getName(); | ||
|
|
||
| if (MI.isFunctionLike()) { | ||
| *OS << '('; | ||
|
|
@@ -182,6 +184,8 @@ class PrintPPOutputPPCallbacks : public PPCallbacks { | |
| void PragmaExecCharsetPop(SourceLocation Loc) override; | ||
| void PragmaAssumeNonNullBegin(SourceLocation Loc) override; | ||
| void PragmaAssumeNonNullEnd(SourceLocation Loc) override; | ||
| void PragmaSetPPState(SourceLocation Loc, IdentifierInfo *MacroName, | ||
| std::uint64_t Value) override; | ||
|
|
||
| /// Insert whitespace before emitting the next token. | ||
| /// | ||
|
|
@@ -559,22 +563,38 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, StringRef S) { | |
| /// MacroDefined - This hook is called whenever a macro definition is seen. | ||
| void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, | ||
| const MacroDirective *MD) { | ||
| bool ShouldEmitDefine = true; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It isn't clear to me what we're doing here? This change and the one in PrintMacroDefinition seem odd? What am I missign?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This handles printing macro definitions (if doing that is enabled); basically, the idea here is that even if we don’t want to print macro definitions, we still need to emit a pragma for The changes to |
||
| const MacroInfo *MI = MD->getMacroInfo(); | ||
| SourceLocation DefLoc = MI->getDefinitionLoc(); | ||
|
|
||
| // Print out macro definitions in -dD mode and when we have -fdirectives-only | ||
| // for C++20 header units. | ||
| if ((!DumpDefines && !DirectivesOnly) || | ||
| // Ignore __FILE__ etc. | ||
| MI->isBuiltinMacro()) | ||
| return; | ||
|
|
||
| SourceLocation DefLoc = MI->getDefinitionLoc(); | ||
| if (DirectivesOnly && !MI->isUsed()) { | ||
| MI->isBuiltinMacro()) { | ||
| ShouldEmitDefine = false; | ||
| } else if (DirectivesOnly && !MI->isUsed()) { | ||
| SourceManager &SM = PP.getSourceManager(); | ||
| if (SM.isInPredefinedFile(DefLoc)) | ||
| return; | ||
| ShouldEmitDefine = false; | ||
| } | ||
|
|
||
| IdentifierInfo *MacroName = MacroNameTok.getIdentifierInfo(); | ||
| if (!ShouldEmitDefine) { | ||
| // Preserve macro definitions of macros that can be used with | ||
| // '#pragma clang __set_pp_state' as pragmas if printing '#define's | ||
| // is disabled. | ||
| if (PP.isPragmaSetPPStateMacro(MacroName)) { | ||
| MoveToLine(DefLoc, /*RequireStartOfLine=*/true); | ||
| *OS << "#pragma clang __set_pp_state " << MacroName->getName(); | ||
| PrintMacroDefinition(/*II=*/nullptr, *MI, PP, OS); | ||
| setEmittedDirectiveOnThisLine(); | ||
| } | ||
| return; | ||
| } | ||
|
|
||
| MoveToLine(DefLoc, /*RequireStartOfLine=*/true); | ||
| PrintMacroDefinition(*MacroNameTok.getIdentifierInfo(), *MI, PP, OS); | ||
| PrintMacroDefinition(MacroName, *MI, PP, OS); | ||
| setEmittedDirectiveOnThisLine(); | ||
| } | ||
|
|
||
|
|
@@ -752,6 +772,15 @@ PragmaAssumeNonNullEnd(SourceLocation Loc) { | |
| setEmittedDirectiveOnThisLine(); | ||
| } | ||
|
|
||
| void PrintPPOutputPPCallbacks::PragmaSetPPState(SourceLocation Loc, | ||
| IdentifierInfo *MacroName, | ||
| std::uint64_t Value) { | ||
| MoveToLine(Loc, /*RequireStartOfLine=*/true); | ||
| *OS << "#pragma clang __set_pp_state " << MacroName->getName() << " " | ||
| << Value; | ||
| setEmittedDirectiveOnThisLine(); | ||
| } | ||
|
|
||
| void PrintPPOutputPPCallbacks::HandleWhitespaceBeforeTok(const Token &Tok, | ||
| bool RequireSpace, | ||
| bool RequireSameLine) { | ||
|
|
@@ -1093,7 +1122,7 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { | |
| // Ignore computed macros like __LINE__ and friends. | ||
| if (MI.isBuiltinMacro()) continue; | ||
|
|
||
| PrintMacroDefinition(*MacrosByID[i].first, MI, PP, OS); | ||
| PrintMacroDefinition(MacrosByID[i].first, MI, PP, OS); | ||
| *OS << '\n'; | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // RUN: %clang_cc1 -E -verify %s | ||
|
|
||
| #pragma clang __set_pp_state // expected-error {{expected identifier after '#pragma clang __set_pp_state'}} | ||
| #pragma clang __set_pp_state 123984 // expected-error {{expected identifier after '#pragma clang __set_pp_state'}} | ||
|
|
||
| #pragma clang __set_pp_state foo // expected-error {{invalid argument 'foo' in '#pragma clang __set_pp_state'}} | ||
| #pragma clang __set_pp_state void // expected-error {{invalid argument 'void' in '#pragma clang __set_pp_state'}} | ||
|
|
||
| #pragma clang __set_pp_state __GLIBCXX__ foo // expected-error {{expected integer after '#pragma clang __set_pp_state __GLIBCXX__'}} | ||
| #pragma clang __set_pp_state __GLIBCXX__ 100000000000000000000000000000 // expected-error {{expected integer after '#pragma clang __set_pp_state __GLIBCXX__'}} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we expect boolean, binary interer or hex integer literals to work? Maybe check char and string literals. nullptr?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, currently, we always generate a decimal literal so that’s the only thing we need to support I think since this isn’t supposed to be user-facing anyway. Anything that’s not a numeric literal would be rejected here since that’s what we check for; I can add some tests for that if you’d like
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More tests here seems like a good thing.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Opened #217735 for this |
||
| #pragma clang __set_pp_state __GLIBCXX__ 42.0 // expected-error {{expected integer after '#pragma clang __set_pp_state __GLIBCXX__'}} | ||
|
|
||
| #pragma clang __set_pp_state __GLIBCXX__ 42L | ||
| #pragma clang __set_pp_state __GLIBCXX__ 42 | ||
|
|
||
| // Check that we treat the identifier after '__set_pp_state' literally. | ||
| #define MACRO __GLIBCXX__ | ||
| #pragma clang __set_pp_state MACRO // expected-error {{invalid argument 'MACRO' in '#pragma clang __set_pp_state'}} | ||
|
|
||
| // Check that we treat '__set_pp_state' literally. | ||
| #define __set_pp_state foobar | ||
| #pragma clang __set_pp_state __GLIBCXX__ 42 | ||
|
|
||
| // The pragma does *not* define __GLIBCXX__! | ||
| #ifdef __GLIBCXX__ | ||
| # error __set_pp_state __GLIBCXX__ should not define __GLIBCXX__ | ||
| #endif | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is neither needed nor used
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it being used; we need an
IdentifierInfo *for the macro names we care about and we don't want to re-create theIdentifierInfo *each time so we cache it.I'd rather these were grouped with the rest of them towards the top of the class though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my comment below. we are gonna parse that once per TU
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, we're not going to parse it often, but I don't see what the problem is with following the usual pattern of comparing
IdentifierInfo *, either. I don't insist one way or the other.Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is true, but we do the comparison against
__GLIBCXX__every time we print a#pragmain-Emode; whether we care about that, I don’t know; we can probably get rid ofIdent__set_pp_statethoughThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of those are specifically predefined/builtin macros; we also have groups of cached
IdentifierInfo*s elsewhere in the preprocessor, so I felt putting these here made more senseThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(via
isPragmaSetPPStateMacro())