From c0b4928df87a856696aee603ca994739df476675 Mon Sep 17 00:00:00 2001 From: Alexander Kornienko Date: Wed, 29 Aug 2012 16:56:24 +0000 Subject: [PATCH] Fixed a problem with #pragma push_macro/pop_macro implementation. Summary: The problem was with the following sequence: #pragma push_macro("long") #undef long #pragma pop_macro("long") in case when "long" didn't represent a macro. Fixed crash and removed code duplication for #undef/pop_macro case. Added regression tests. Reviewers: doug.gregor, klimek Reviewed By: doug.gregor CC: cfe-commits, chapuni Differential Revision: http://llvm-reviews.chandlerc.com/D31 llvm-svn: 162845 --- clang/include/clang/Lex/Preprocessor.h | 2 ++ clang/lib/Lex/PPDirectives.cpp | 5 +---- clang/lib/Lex/PPMacroExpansion.cpp | 9 +++++++++ clang/lib/Lex/Pragma.cpp | 9 +++++++-- .../test/Preprocessor/pragma-pushpop-macro.c | 19 ++++++++++++++++++- 5 files changed, 37 insertions(+), 7 deletions(-) diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index fca5796068b8..adc6b240e961 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -470,6 +470,8 @@ public: /// \brief Specify a macro for this identifier. void setMacroInfo(IdentifierInfo *II, MacroInfo *MI, bool LoadedFromAST = false); + /// \brief Undefine a macro for this identifier. + void clearMacroInfo(IdentifierInfo *II); /// macro_iterator/macro_begin/macro_end - This allows you to walk the macro /// history table. Currently defined macros have diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 6de0e4a9f36e..738bed36ba12 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1921,10 +1921,7 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); MI->setUndefLoc(MacroNameTok.getLocation()); - IdentifierInfo *II = MacroNameTok.getIdentifierInfo(); - II->setHasMacroDefinition(false); - if (II->isFromAST()) - II->setChangedSinceDeserialization(); + clearMacroInfo(MacroNameTok.getIdentifierInfo()); } diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 936b37009c12..3f27236cac3c 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -57,6 +57,15 @@ void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI, II->setChangedSinceDeserialization(); } +/// \brief Undefine a macro for this identifier. +void Preprocessor::clearMacroInfo(IdentifierInfo *II) { + assert(II->hasMacroDefinition() && "Macro is not defined!"); + assert(Macros[II]->getUndefLoc().isValid() && "Macro is still defined!"); + II->setHasMacroDefinition(false); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); +} + /// RegisterBuiltinMacro - Register the specified identifier in the identifier /// table and mark it as a builtin macro to be expanded. static IdentifierInfo *RegisterBuiltinMacro(Preprocessor &PP, const char *Name){ diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index acf5c74556f4..62ef8bfbcdc6 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -737,13 +737,18 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { if (MacroInfo *CurrentMI = getMacroInfo(IdentInfo)) { if (CurrentMI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc()); + CurrentMI->setUndefLoc(MessageLoc); } // Get the MacroInfo we want to reinstall. MacroInfo *MacroToReInstall = iter->second.back(); - // Reinstall the previously pushed macro. - setMacroInfo(IdentInfo, MacroToReInstall); + if (MacroToReInstall) { + // Reinstall the previously pushed macro. + setMacroInfo(IdentInfo, MacroToReInstall); + } else if (IdentInfo->hasMacroDefinition()) { + clearMacroInfo(IdentInfo); + } // Pop PragmaPushMacroInfo stack. iter->second.pop_back(); diff --git a/clang/test/Preprocessor/pragma-pushpop-macro.c b/clang/test/Preprocessor/pragma-pushpop-macro.c index 08a65704e4cb..0aee074c55c7 100644 --- a/clang/test/Preprocessor/pragma-pushpop-macro.c +++ b/clang/test/Preprocessor/pragma-pushpop-macro.c @@ -31,6 +31,22 @@ int pmy1 = Y; #define Y 4 int pmy2 = Y; +// The sequence push, define/undef, pop caused problems if macro was not +// previously defined. +#pragma push_macro("PREVIOUSLY_UNDEFINED1") +#undef PREVIOUSLY_UNDEFINED1 +#pragma pop_macro("PREVIOUSLY_UNDEFINED1") +#ifndef PREVIOUSLY_UNDEFINED1 +int Q; +#endif + +#pragma push_macro("PREVIOUSLY_UNDEFINED2") +#define PREVIOUSLY_UNDEFINED2 +#pragma pop_macro("PREVIOUSLY_UNDEFINED2") +#ifndef PREVIOUSLY_UNDEFINED2 +int P; +#endif + // CHECK: int pmx0 = 1 // CHECK: int pmy0 = 2 // CHECK: int pmx1 = 1 @@ -38,4 +54,5 @@ int pmy2 = Y; // CHECK: int pmx3 = 1 // CHECK: int pmy1 = 3 // CHECK: int pmy2 = 4 - +// CHECK: int Q; +// CHECK: int P;