Skip to content

Commit cf55ae7

Browse files
committed
[Modules] Fix an identifier hiding a function-like macro definition.
We emit a macro definition only in a module defining it. But it means that if another module has an identifier with the same name as the macro, the users of such module won't be able to use the macro anymore. Fix by storing that an identifier has a macro definition that's not in a current module (`MacroDirectivesOffset == 0`). This way `IdentifierLookupVisitor` knows not to stop at the first module with an identifier but to keep checking included modules for the actual macro definition. Fixes issue #32040. rdar://30258278
1 parent 357e380 commit cf55ae7

File tree

4 files changed

+57
-10
lines changed

4 files changed

+57
-10
lines changed

clang/lib/Serialization/ASTReader.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
11311131
bool HasRevertedTokenIDToIdentifier = readBit(Bits);
11321132
bool Poisoned = readBit(Bits);
11331133
bool ExtensionToken = readBit(Bits);
1134-
bool HadMacroDefinition = readBit(Bits);
1134+
bool HasMacroDefinition = readBit(Bits);
11351135

11361136
assert(Bits == 0 && "Extra bits in the identifier?");
11371137
DataLen -= sizeof(uint16_t) * 2;
@@ -1151,14 +1151,17 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k,
11511151
"Incorrect C++ operator keyword flag");
11521152
(void)CPlusPlusOperatorKeyword;
11531153

1154-
// If this identifier is a macro, deserialize the macro
1155-
// definition.
1156-
if (HadMacroDefinition) {
1154+
// If this identifier has a macro definition, deserialize it or notify the
1155+
// visitor the actual definition is in a different module.
1156+
if (HasMacroDefinition) {
11571157
uint32_t MacroDirectivesOffset =
11581158
endian::readNext<uint32_t, llvm::endianness::little>(d);
11591159
DataLen -= 4;
11601160

1161-
Reader.addPendingMacro(II, &F, MacroDirectivesOffset);
1161+
if (MacroDirectivesOffset)
1162+
Reader.addPendingMacro(II, &F, MacroDirectivesOffset);
1163+
else
1164+
hasMacroDefinitionInDependencies = true;
11621165
}
11631166

11641167
Reader.SetIdentifierInfo(ID, II);
@@ -2419,6 +2422,9 @@ namespace {
24192422
// declarations it needs.
24202423
++NumIdentifierLookupHits;
24212424
Found = *Pos;
2425+
if (Trait.hasMoreInformationInDependencies())
2426+
// Look for the identifier in extra modules as they contain more info.
2427+
return false;
24222428
return true;
24232429
}
24242430

clang/lib/Serialization/ASTReaderInternals.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase {
286286
// identifier that was constructed before the AST file was read.
287287
IdentifierInfo *KnownII;
288288

289+
bool hasMacroDefinitionInDependencies = false;
290+
289291
public:
290292
using data_type = IdentifierInfo *;
291293

@@ -300,6 +302,10 @@ class ASTIdentifierLookupTrait : public ASTIdentifierLookupTraitBase {
300302
IdentifierID ReadIdentifierID(const unsigned char *d);
301303

302304
ASTReader &getReader() const { return Reader; }
305+
306+
bool hasMoreInformationInDependencies() const {
307+
return hasMacroDefinitionInDependencies;
308+
}
303309
};
304310

305311
/// The on-disk hash table used to contain information about

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3792,7 +3792,10 @@ bool IsInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset,
37923792
II->getNotableIdentifierID() != tok::NotableIdentifierKind::not_notable ||
37933793
II->getBuiltinID() != Builtin::ID::NotBuiltin ||
37943794
II->getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword;
3795-
if (MacroOffset || II->isPoisoned() || (!IsModule && IsInteresting) ||
3795+
if (MacroOffset ||
3796+
(II->hasMacroDefinition() &&
3797+
II->hasFETokenInfoChangedSinceDeserialization()) ||
3798+
II->isPoisoned() || (!IsModule && IsInteresting) ||
37963799
II->hasRevertedTokenIDToIdentifier() ||
37973800
(NeedDecls && II->getFETokenInfo()))
37983801
return true;
@@ -3871,7 +3874,8 @@ class ASTIdentifierTableTrait {
38713874
if (isInterestingIdentifier(II, MacroOffset)) {
38723875
DataLen += 2; // 2 bytes for builtin ID
38733876
DataLen += 2; // 2 bytes for flags
3874-
if (MacroOffset)
3877+
if (MacroOffset || (II->hasMacroDefinition() &&
3878+
II->hasFETokenInfoChangedSinceDeserialization()))
38753879
DataLen += 4; // MacroDirectives offset.
38763880

38773881
if (NeedDecls && IdResolver)
@@ -3902,15 +3906,17 @@ class ASTIdentifierTableTrait {
39023906
assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
39033907
LE.write<uint16_t>(Bits);
39043908
Bits = 0;
3905-
bool HadMacroDefinition = MacroOffset != 0;
3906-
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
3909+
bool HasMacroDefinition =
3910+
(MacroOffset != 0) || (II->hasMacroDefinition() &&
3911+
II->hasFETokenInfoChangedSinceDeserialization());
3912+
Bits = (Bits << 1) | unsigned(HasMacroDefinition);
39073913
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
39083914
Bits = (Bits << 1) | unsigned(II->isPoisoned());
39093915
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
39103916
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
39113917
LE.write<uint16_t>(Bits);
39123918

3913-
if (HadMacroDefinition)
3919+
if (HasMacroDefinition)
39143920
LE.write<uint32_t>(MacroOffset);
39153921

39163922
if (NeedDecls && IdResolver) {

clang/test/Modules/shadow-macro.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache \
4+
// RUN: -fsyntax-only %t/test.c -verify
5+
// Test again with the populated module cache.
6+
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache \
7+
// RUN: -fsyntax-only %t/test.c -verify
8+
9+
// Test that an identifier with the same name as a macro doesn't hide this
10+
// macro from the includers.
11+
12+
//--- macro-definition.h
13+
#define __P(protos) ()
14+
#define __Q(protos) ()
15+
16+
//--- macro-transitive.h
17+
#include "macro-definition.h"
18+
void test(int __P) {} // not "interesting" identifier
19+
struct __Q {}; // "interesting" identifier
20+
21+
//--- module.modulemap
22+
module MacroDefinition { header "macro-definition.h" export * }
23+
module MacroTransitive { header "macro-transitive.h" export * }
24+
25+
//--- test.c
26+
// expected-no-diagnostics
27+
#include "macro-transitive.h"
28+
void foo __P(());
29+
void bar __Q(());

0 commit comments

Comments
 (0)