Skip to content

Commit 81739c3

Browse files
authored
[Modules] Fix an identifier hiding a function-like macro definition. (#135471)
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 52e0337 commit 81739c3

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

clang/lib/Serialization/ASTReader.cpp

Lines changed: 12 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,10 @@ 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;
2428+
}
24222429
return true;
24232430
}
24242431

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
@@ -3795,7 +3795,10 @@ bool IsInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset,
37953795
II->getNotableIdentifierID() != tok::NotableIdentifierKind::not_notable ||
37963796
II->getBuiltinID() != Builtin::ID::NotBuiltin ||
37973797
II->getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword;
3798-
if (MacroOffset || II->isPoisoned() || (!IsModule && IsInteresting) ||
3798+
if (MacroOffset ||
3799+
(II->hasMacroDefinition() &&
3800+
II->hasFETokenInfoChangedSinceDeserialization()) ||
3801+
II->isPoisoned() || (!IsModule && IsInteresting) ||
37993802
II->hasRevertedTokenIDToIdentifier() ||
38003803
(NeedDecls && II->getFETokenInfo()))
38013804
return true;
@@ -3874,7 +3877,8 @@ class ASTIdentifierTableTrait {
38743877
if (isInterestingIdentifier(II, MacroOffset)) {
38753878
DataLen += 2; // 2 bytes for builtin ID
38763879
DataLen += 2; // 2 bytes for flags
3877-
if (MacroOffset)
3880+
if (MacroOffset || (II->hasMacroDefinition() &&
3881+
II->hasFETokenInfoChangedSinceDeserialization()))
38783882
DataLen += 4; // MacroDirectives offset.
38793883

38803884
if (NeedDecls && IdResolver)
@@ -3905,15 +3909,17 @@ class ASTIdentifierTableTrait {
39053909
assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader.");
39063910
LE.write<uint16_t>(Bits);
39073911
Bits = 0;
3908-
bool HadMacroDefinition = MacroOffset != 0;
3909-
Bits = (Bits << 1) | unsigned(HadMacroDefinition);
3912+
bool HasMacroDefinition =
3913+
(MacroOffset != 0) || (II->hasMacroDefinition() &&
3914+
II->hasFETokenInfoChangedSinceDeserialization());
3915+
Bits = (Bits << 1) | unsigned(HasMacroDefinition);
39103916
Bits = (Bits << 1) | unsigned(II->isExtensionToken());
39113917
Bits = (Bits << 1) | unsigned(II->isPoisoned());
39123918
Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier());
39133919
Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword());
39143920
LE.write<uint16_t>(Bits);
39153921

3916-
if (HadMacroDefinition)
3922+
if (HasMacroDefinition)
39173923
LE.write<uint32_t>(MacroOffset);
39183924

39193925
if (NeedDecls && IdResolver) {
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)