From: Douglas Gregor Date: Fri, 12 Oct 2012 00:16:50 +0000 (+0000) Subject: Track which particular submodule #undef's a macro, so that the actual X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=54c8a40ed658676b1f3f983728feae488c501477;p=clang Track which particular submodule #undef's a macro, so that the actual #undef only occurs if that submodule is imported. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@165773 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Serialization/ASTReader.h b/include/clang/Serialization/ASTReader.h index 4e8531a820..d23e7c5bf4 100644 --- a/include/clang/Serialization/ASTReader.h +++ b/include/clang/Serialization/ASTReader.h @@ -395,7 +395,10 @@ private: /// global macro ID to produce a local ID. GlobalMacroMapType GlobalMacroMap; - typedef llvm::DenseMap MacroUpdatesMap; + typedef llvm::DenseMap, 1> > + MacroUpdatesMap; /// \brief Mapping from (global) macro IDs to the set of updates to be /// performed to the corresponding macro. @@ -417,30 +420,50 @@ private: /// \brief An entity that has been hidden. class HiddenName { - /// \brief The hidden declaration or macro. - llvm::PointerUnion DeclOrMacro; + public: + enum NameKind { + Declaration, + MacroVisibility, + MacroUndef + } Kind; + + private: + unsigned Loc; + + union { + Decl *D; + MacroInfo *MI; + }; - /// \brief The name being defined to a macro, for the macro case. - IdentifierInfo *Identifier; + IdentifierInfo *Id; public: - HiddenName(Decl *D) : DeclOrMacro(D), Identifier() { } + HiddenName(Decl *D) : Kind(Declaration), Loc(), D(D), Id() { } + HiddenName(IdentifierInfo *II, MacroInfo *MI) - : DeclOrMacro(MI), Identifier(II) { } + : Kind(MacroVisibility), Loc(), MI(MI), Id(II) { } + + HiddenName(IdentifierInfo *II, MacroInfo *MI, SourceLocation Loc) + : Kind(MacroUndef), Loc(Loc.getRawEncoding()), MI(MI), Id(II) { } - bool isDecl() const { return DeclOrMacro.is(); } - bool isMacro() const { return !isDecl(); } + NameKind getKind() const { return Kind; } Decl *getDecl() const { - assert(isDecl() && "Hidden name is not a declaration"); - return DeclOrMacro.get(); + assert(getKind() == Declaration && "Hidden name is not a declaration"); + return D; } std::pair getMacro() const { - assert(isMacro() && "Hidden name is not a macro!"); - return std::make_pair(Identifier, DeclOrMacro.get()); + assert((getKind() == MacroUndef || getKind() == MacroVisibility) + && "Hidden name is not a macro!"); + return std::make_pair(Id, MI); } - }; + + SourceLocation getMacroUndefLoc() const { + assert(getKind() == MacroUndef && "Hidden name is not an undef!"); + return SourceLocation::getFromRawEncoding(Loc); + } +}; /// \brief A set of hidden declarations. typedef llvm::SmallVector diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index dc3a45652a..3959671fda 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -87,11 +87,13 @@ void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI, } // Find the end of the definition chain. - MacroInfo *Prev = StoredMI; - MacroInfo *PrevPrev; + MacroInfo *Prev; + MacroInfo *PrevPrev = StoredMI; bool Ambiguous = StoredMI->isAmbiguous(); bool MatchedOther = false; do { + Prev = PrevPrev; + // If the macros are not identical, we have an ambiguity. if (!Prev->isIdenticalTo(*MI, *this)) { if (!Ambiguous) { @@ -125,25 +127,29 @@ void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI, void Preprocessor::makeLoadedMacroInfoVisible(IdentifierInfo *II, MacroInfo *MI) { assert(MI->isFromAST() && "Macro must be from the AST"); - assert(MI->isDefined() && "Macro is not visible"); MacroInfo *&StoredMI = Macros[II]; if (StoredMI == MI) { // Easy case: this is the first macro anyway. - II->setHasMacroDefinition(true); + II->setHasMacroDefinition(MI->isDefined()); return; } // Go find the macro and pull it out of the list. - // FIXME: Yes, this is O(N), and making a pile of macros visible would be - // quadratic. + // FIXME: Yes, this is O(N), and making a pile of macros visible or hidden + // would be quadratic, but it's extremely rare. MacroInfo *Prev = StoredMI; while (Prev->getPreviousDefinition() != MI) Prev = Prev->getPreviousDefinition(); Prev->setPreviousDefinition(MI->getPreviousDefinition()); + MI->setPreviousDefinition(0); // Add the macro back to the list. addLoadedMacroInfo(II, MI); + + II->setHasMacroDefinition(StoredMI->isDefined()); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); } /// \brief Undefine a macro for this identifier. diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 8f18eb8465..d22e85b18f 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -1364,9 +1364,28 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID); if (Update != MacroUpdates.end()) { if (MI->getUndefLoc().isInvalid()) { - MI->setUndefLoc(Update->second.UndefLoc); - if (PPMutationListener *Listener = PP.getPPMutationListener()) - Listener->UndefinedMacro(MI); + for (unsigned I = 0, N = Update->second.size(); I != N; ++I) { + bool Hidden = false; + if (unsigned SubmoduleID = Update->second[I].first) { + if (Module *Owner = getSubmodule(SubmoduleID)) { + if (Owner->NameVisibility == Module::Hidden) { + // Note that this #undef is hidden. + Hidden = true; + + // Record this hiding for later. + HiddenNamesMap[Owner].push_back( + HiddenName(II, MI, Update->second[I].second.UndefLoc)); + } + } + } + + if (!Hidden) { + MI->setUndefLoc(Update->second[I].second.UndefLoc); + if (PPMutationListener *Listener = PP.getPPMutationListener()) + Listener->UndefinedMacro(MI); + break; + } + } } MacroUpdates.erase(Update); } @@ -2517,7 +2536,11 @@ ASTReader::ReadASTBlock(ModuleFile &F) { if (I == N) break; - MacroUpdates[ID].UndefLoc = ReadSourceLocation(F, Record, I); + SourceLocation UndefLoc = ReadSourceLocation(F, Record, I); + SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);; + MacroUpdate Update; + Update.UndefLoc = UndefLoc; + MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update)); } break; } @@ -2619,15 +2642,30 @@ ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) { void ASTReader::makeNamesVisible(const HiddenNames &Names) { for (unsigned I = 0, N = Names.size(); I != N; ++I) { - if (Names[I].isDecl()) { + switch (Names[I].getKind()) { + case HiddenName::Declaration: Names[I].getDecl()->Hidden = false; - continue; + break; + + case HiddenName::MacroVisibility: { + std::pair Macro = Names[I].getMacro(); + Macro.second->setHidden(!Macro.second->isPublic()); + if (Macro.second->isDefined()) { + PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + } + break; } - std::pair Macro = Names[I].getMacro(); - Macro.second->setHidden(!Macro.second->isPublic()); - if (Macro.second->isDefined()) { - PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + case HiddenName::MacroUndef: { + std::pair Macro = Names[I].getMacro(); + if (Macro.second->isDefined()) { + Macro.second->setUndefLoc(Names[I].getMacroUndefLoc()); + if (PPMutationListener *Listener = PP.getPPMutationListener()) + Listener->UndefinedMacro(Macro.second); + PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + } + break; + } } } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 28f78c6181..2fbe4bf6a3 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -3686,6 +3686,7 @@ void ASTWriter::WriteMacroUpdates() { I != E; ++I) { addMacroRef(I->first, Record); AddSourceLocation(I->second.UndefLoc, Record); + Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc)); } Stream.EmitRecord(MACRO_UPDATES, Record); } diff --git a/test/Modules/Inputs/macros_left.h b/test/Modules/Inputs/macros_left.h index a2f287e668..cd05693891 100644 --- a/test/Modules/Inputs/macros_left.h +++ b/test/Modules/Inputs/macros_left.h @@ -1,4 +1,4 @@ -#include "macros_top.h" +@__experimental_modules_import macros_top; #define LEFT unsigned long #undef TOP_LEFT_UNDEF diff --git a/test/Modules/Inputs/macros_right.h b/test/Modules/Inputs/macros_right.h index a4a1e2e0cf..e16a64b50a 100644 --- a/test/Modules/Inputs/macros_right.h +++ b/test/Modules/Inputs/macros_right.h @@ -1,4 +1,4 @@ -#include "macros_top.h" +@__experimental_modules_import macros_top; #define RIGHT unsigned short diff --git a/test/Modules/Inputs/macros_right_undef.h b/test/Modules/Inputs/macros_right_undef.h new file mode 100644 index 0000000000..49473e36f0 --- /dev/null +++ b/test/Modules/Inputs/macros_right_undef.h @@ -0,0 +1 @@ +#undef TOP_RIGHT_UNDEF diff --git a/test/Modules/Inputs/macros_top.h b/test/Modules/Inputs/macros_top.h index 5264cea2d1..9c3f3c071f 100644 --- a/test/Modules/Inputs/macros_top.h +++ b/test/Modules/Inputs/macros_top.h @@ -11,3 +11,6 @@ #define TOP_RIGHT_REDEF int + +#define TOP_RIGHT_UNDEF int + diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index b26234382b..4200535a5a 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -28,6 +28,9 @@ module macros_left { module macros_right { header "macros_right.h" export * + explicit module undef { + header "macros_right_undef.h" + } } module macros { header "macros.h" } module category_top { header "category_top.h" } diff --git a/test/Modules/macros.c b/test/Modules/macros.c index 8f6a20aa93..8db3915f24 100644 --- a/test/Modules/macros.c +++ b/test/Modules/macros.c @@ -107,10 +107,6 @@ void test1() { # error TOP should be visible #endif -#ifndef TOP_LEFT_UNDEF -# error TOP_LEFT_UNDEF should be visible -#endif - void test2() { int i; float f; @@ -129,3 +125,13 @@ void test3() { double d; LEFT_RIGHT_DIFFERENT *dp = &d; // okay } + +#ifndef TOP_RIGHT_UNDEF +# error TOP_RIGHT_UNDEF should still be defined +#endif + +@__experimental_modules_import macros_right.undef; + +#ifdef TOP_RIGHT_UNDEF +# error TOP_RIGHT_UNDEF should not be defined +#endif