diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 02c31dff620ec..58d3d33b31644 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -1131,7 +1131,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, bool HasRevertedTokenIDToIdentifier = readBit(Bits); bool Poisoned = readBit(Bits); bool ExtensionToken = readBit(Bits); - bool HadMacroDefinition = readBit(Bits); + bool HasMacroDefinition = readBit(Bits); assert(Bits == 0 && "Extra bits in the identifier?"); DataLen -= sizeof(uint16_t) * 2; @@ -1151,14 +1151,17 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, "Incorrect C++ operator keyword flag"); (void)CPlusPlusOperatorKeyword; - // If this identifier is a macro, deserialize the macro - // definition. - if (HadMacroDefinition) { + // If this identifier has a macro definition, deserialize it or notify the + // visitor the actual definition is in a different module. + if (HasMacroDefinition) { uint32_t MacroDirectivesOffset = endian::readNext(d); DataLen -= 4; - Reader.addPendingMacro(II, &F, MacroDirectivesOffset); + if (MacroDirectivesOffset) + Reader.addPendingMacro(II, &F, MacroDirectivesOffset); + else + hasMacroDefinitionInDependencies = true; } Reader.SetIdentifierInfo(ID, II); @@ -2419,6 +2422,10 @@ namespace { // declarations it needs. ++NumIdentifierLookupHits; Found = *Pos; + if (Trait.hasMoreInformationInDependencies()) { + // Look for the identifier in extra modules as they contain more info. + return false; + } return true; } diff --git a/clang/lib/Serialization/ASTReaderInternals.h b/clang/lib/Serialization/ASTReaderInternals.h index 353e0a53cad9b..4a7794889b039 100644 --- a/clang/lib/Serialization/ASTReaderInternals.h +++ b/clang/lib/Serialization/ASTReaderInternals.h @@ -286,6 +286,8 @@ class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase { // identifier that was constructed before the AST file was read. IdentifierInfo *KnownII; + bool hasMacroDefinitionInDependencies = false; + public: using data_type = IdentifierInfo *; @@ -300,6 +302,10 @@ class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase { IdentifierID ReadIdentifierID(const unsigned char *d); ASTReader &getReader() const { return Reader; } + + bool hasMoreInformationInDependencies() const { + return hasMacroDefinitionInDependencies; + } }; /// The on-disk hash table used to contain information about diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a48c05061626a..05a3b8f08029f 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3792,7 +3792,10 @@ bool IsInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset, II->getNotableIdentifierID() != tok::NotableIdentifierKind::not_notable || II->getBuiltinID() != Builtin::ID::NotBuiltin || II->getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword; - if (MacroOffset || II->isPoisoned() || (!IsModule && IsInteresting) || + if (MacroOffset || + (II->hasMacroDefinition() && + II->hasFETokenInfoChangedSinceDeserialization()) || + II->isPoisoned() || (!IsModule && IsInteresting) || II->hasRevertedTokenIDToIdentifier() || (NeedDecls && II->getFETokenInfo())) return true; @@ -3871,7 +3874,8 @@ class ASTIdentifierTableTrait { if (isInterestingIdentifier(II, MacroOffset)) { DataLen += 2; // 2 bytes for builtin ID DataLen += 2; // 2 bytes for flags - if (MacroOffset) + if (MacroOffset || (II->hasMacroDefinition() && + II->hasFETokenInfoChangedSinceDeserialization())) DataLen += 4; // MacroDirectives offset. if (NeedDecls && IdResolver) @@ -3902,15 +3906,17 @@ class ASTIdentifierTableTrait { assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader."); LE.write(Bits); Bits = 0; - bool HadMacroDefinition = MacroOffset != 0; - Bits = (Bits << 1) | unsigned(HadMacroDefinition); + bool HasMacroDefinition = + (MacroOffset != 0) || (II->hasMacroDefinition() && + II->hasFETokenInfoChangedSinceDeserialization()); + Bits = (Bits << 1) | unsigned(HasMacroDefinition); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); LE.write(Bits); - if (HadMacroDefinition) + if (HasMacroDefinition) LE.write(MacroOffset); if (NeedDecls && IdResolver) { diff --git a/clang/test/Modules/macro-identifier-hiding.c b/clang/test/Modules/macro-identifier-hiding.c new file mode 100644 index 0000000000000..4cd7cf0500322 --- /dev/null +++ b/clang/test/Modules/macro-identifier-hiding.c @@ -0,0 +1,29 @@ +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache \ +// RUN: -fsyntax-only %t/test.c -verify +// Test again with the populated module cache. +// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache \ +// RUN: -fsyntax-only %t/test.c -verify + +// Test that an identifier with the same name as a macro doesn't hide this +// macro from the includers. + +//--- macro-definition.h +#define __P(protos) () +#define __Q(protos) () + +//--- macro-transitive.h +#include "macro-definition.h" +void test(int __P) {} // not "interesting" identifier +struct __Q {}; // "interesting" identifier + +//--- module.modulemap +module MacroDefinition { header "macro-definition.h" export * } +module MacroTransitive { header "macro-transitive.h" export * } + +//--- test.c +// expected-no-diagnostics +#include "macro-transitive.h" +void foo __P(()); +void bar __Q(());