Skip to content

Commit 363c98b

Browse files
committed
Revert "[Modules] Remove unnecessary check when generating name lookup table in ASTWriter"
This reverts commit bc95f27, originally db987b9. clang/test/Modules/pr61065.cppm is retained to make relands show less diff. There are other module-related issues that were not caught, related to false positive errors like "error: no matching constructor for initialization of 'union (anonymous union at ..." Reopen #61065
1 parent 42c2fa6 commit 363c98b

File tree

3 files changed

+73
-38
lines changed

3 files changed

+73
-38
lines changed

clang/include/clang/Serialization/ASTWriter.h

+1
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ class ASTWriter : public ASTDeserializationListener,
514514
void WriteTypeAbbrevs();
515515
void WriteType(QualType T);
516516

517+
bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
517518
bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC);
518519

519520
void GenerateNameLookupTable(const DeclContext *DC,

clang/lib/Serialization/ASTWriter.cpp

+69-35
Original file line numberDiff line numberDiff line change
@@ -3849,6 +3849,12 @@ class ASTDeclContextNameLookupTrait {
38493849

38503850
} // namespace
38513851

3852+
bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
3853+
DeclContext *DC) {
3854+
return Result.hasExternalDecls() &&
3855+
DC->hasNeedToReconcileExternalVisibleStorage();
3856+
}
3857+
38523858
bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result,
38533859
DeclContext *DC) {
38543860
for (auto *D : Result.getLookupResult())
@@ -3879,17 +3885,20 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
38793885
// order.
38803886
SmallVector<DeclarationName, 16> Names;
38813887

3882-
// We also track whether we're writing out the DeclarationNameKey for
3883-
// constructors or conversion functions.
3884-
bool IncludeConstructorNames = false;
3885-
bool IncludeConversionNames = false;
3888+
// We also build up small sets of the constructor and conversion function
3889+
// names which are visible.
3890+
llvm::SmallPtrSet<DeclarationName, 8> ConstructorNameSet, ConversionNameSet;
3891+
3892+
for (auto &Lookup : *DC->buildLookup()) {
3893+
auto &Name = Lookup.first;
3894+
auto &Result = Lookup.second;
38863895

3887-
for (auto &[Name, Result] : *DC->buildLookup()) {
38883896
// If there are no local declarations in our lookup result, we
38893897
// don't need to write an entry for the name at all. If we can't
38903898
// write out a lookup set without performing more deserialization,
38913899
// just skip this entry.
3892-
if (isLookupResultEntirelyExternal(Result, DC))
3900+
if (isLookupResultExternal(Result, DC) &&
3901+
isLookupResultEntirelyExternal(Result, DC))
38933902
continue;
38943903

38953904
// We also skip empty results. If any of the results could be external and
@@ -3906,55 +3915,80 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
39063915
// results for them. This in almost certainly a bug in Clang's name lookup,
39073916
// but that is likely to be hard or impossible to fix and so we tolerate it
39083917
// here by omitting lookups with empty results.
3909-
if (Result.getLookupResult().empty())
3918+
if (Lookup.second.getLookupResult().empty())
39103919
continue;
39113920

3912-
switch (Name.getNameKind()) {
3921+
switch (Lookup.first.getNameKind()) {
39133922
default:
3914-
Names.push_back(Name);
3923+
Names.push_back(Lookup.first);
39153924
break;
39163925

39173926
case DeclarationName::CXXConstructorName:
3918-
IncludeConstructorNames = true;
3927+
assert(isa<CXXRecordDecl>(DC) &&
3928+
"Cannot have a constructor name outside of a class!");
3929+
ConstructorNameSet.insert(Name);
39193930
break;
39203931

39213932
case DeclarationName::CXXConversionFunctionName:
3922-
IncludeConversionNames = true;
3933+
assert(isa<CXXRecordDecl>(DC) &&
3934+
"Cannot have a conversion function name outside of a class!");
3935+
ConversionNameSet.insert(Name);
39233936
break;
39243937
}
39253938
}
39263939

39273940
// Sort the names into a stable order.
39283941
llvm::sort(Names);
39293942

3930-
if (IncludeConstructorNames || IncludeConversionNames) {
3943+
if (auto *D = dyn_cast<CXXRecordDecl>(DC)) {
39313944
// We need to establish an ordering of constructor and conversion function
3932-
// names, and they don't have an intrinsic ordering. We also need to write
3933-
// out all constructor and conversion function results if we write out any
3934-
// of them, because they're all tracked under the same lookup key.
3935-
llvm::SmallPtrSet<DeclarationName, 8> AddedNames;
3936-
for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls()) {
3937-
if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
3938-
auto Name = ChildND->getDeclName();
3939-
switch (Name.getNameKind()) {
3940-
default:
3941-
continue;
3942-
3943-
case DeclarationName::CXXConstructorName:
3944-
if (!IncludeConstructorNames)
3945+
// names, and they don't have an intrinsic ordering.
3946+
3947+
// First we try the easy case by forming the current context's constructor
3948+
// name and adding that name first. This is a very useful optimization to
3949+
// avoid walking the lexical declarations in many cases, and it also
3950+
// handles the only case where a constructor name can come from some other
3951+
// lexical context -- when that name is an implicit constructor merged from
3952+
// another declaration in the redecl chain. Any non-implicit constructor or
3953+
// conversion function which doesn't occur in all the lexical contexts
3954+
// would be an ODR violation.
3955+
auto ImplicitCtorName = Context->DeclarationNames.getCXXConstructorName(
3956+
Context->getCanonicalType(Context->getRecordType(D)));
3957+
if (ConstructorNameSet.erase(ImplicitCtorName))
3958+
Names.push_back(ImplicitCtorName);
3959+
3960+
// If we still have constructors or conversion functions, we walk all the
3961+
// names in the decl and add the constructors and conversion functions
3962+
// which are visible in the order they lexically occur within the context.
3963+
if (!ConstructorNameSet.empty() || !ConversionNameSet.empty())
3964+
for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls())
3965+
if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
3966+
auto Name = ChildND->getDeclName();
3967+
switch (Name.getNameKind()) {
3968+
default:
39453969
continue;
3946-
break;
39473970

3948-
case DeclarationName::CXXConversionFunctionName:
3949-
if (!IncludeConversionNames)
3950-
continue;
3951-
break;
3971+
case DeclarationName::CXXConstructorName:
3972+
if (ConstructorNameSet.erase(Name))
3973+
Names.push_back(Name);
3974+
break;
3975+
3976+
case DeclarationName::CXXConversionFunctionName:
3977+
if (ConversionNameSet.erase(Name))
3978+
Names.push_back(Name);
3979+
break;
3980+
}
3981+
3982+
if (ConstructorNameSet.empty() && ConversionNameSet.empty())
3983+
break;
39523984
}
3953-
// We should include lookup results for this name.
3954-
if (AddedNames.insert(Name).second)
3955-
Names.push_back(Name);
3956-
}
3957-
}
3985+
3986+
assert(ConstructorNameSet.empty() && "Failed to find all of the visible "
3987+
"constructors by walking all the "
3988+
"lexical members of the context.");
3989+
assert(ConversionNameSet.empty() && "Failed to find all of the visible "
3990+
"conversion functions by walking all "
3991+
"the lexical members of the context.");
39583992
}
39593993

39603994
// Next we need to do a lookup with each name into this decl context to fully

clang/test/Modules/pr61065.cppm

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
77
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
88
// RUN: -fprebuilt-module-path=%t
9-
// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \
10-
// RUN: -fprebuilt-module-path=%t
11-
// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify -fprebuilt-module-path=%t
9+
// DISABLED: %clang_cc1 -std=c++20 %t/c.cppm -emit-module-interface -o %t/c.pcm \
10+
// DISABLED: -fprebuilt-module-path=%t
11+
// DISABLED: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify -fprebuilt-module-path=%t
1212

1313
//--- a.cppm
1414
export module a;

0 commit comments

Comments
 (0)