Skip to content

Commit 1d0ee12

Browse files
hokeinVitaNuo
andauthored
Reland "Reland [Modules] Remove unnecessary check when generating name lookup table in ASTWriter" (#139253)
This relands the patch 67b298f, with some more testcases. The `undefined symbol` error mentioned in #61065 (comment) doesn't exist anymore from our internal tests. Fixes #61065, #134739 --------- Co-authored-by: Viktoriia Bakalova <[email protected]>
1 parent 2f9323b commit 1d0ee12

File tree

6 files changed

+90
-84
lines changed

6 files changed

+90
-84
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ Bug Fixes in This Version
582582
``#include`` directive. (#GH138094)
583583
- Fixed a crash during constant evaluation involving invalid lambda captures
584584
(#GH138832)
585+
- Fixed assertion failures when generating name lookup table in modules. (#GH61065, #GH134739)
585586

586587
Bug Fixes to Compiler Builtins
587588
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,8 +592,6 @@ class ASTWriter : public ASTDeserializationListener,
592592
void WriteTypeAbbrevs();
593593
void WriteType(ASTContext &Context, QualType T);
594594

595-
bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
596-
597595
void GenerateSpecializationInfoLookupTable(
598596
const NamedDecl *D, llvm::SmallVectorImpl<const Decl *> &Specializations,
599597
llvm::SmallVectorImpl<char> &LookupTable, bool IsPartial);

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 34 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4504,12 +4504,6 @@ uint64_t ASTWriter::WriteSpecializationInfoLookupTable(
45044504
return Offset;
45054505
}
45064506

4507-
bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
4508-
DeclContext *DC) {
4509-
return Result.hasExternalDecls() &&
4510-
DC->hasNeedToReconcileExternalVisibleStorage();
4511-
}
4512-
45134507
/// Returns ture if all of the lookup result are either external, not emitted or
45144508
/// predefined. In such cases, the lookup result is not interesting and we don't
45154509
/// need to record the result in the current being written module. Return false
@@ -4561,14 +4555,12 @@ void ASTWriter::GenerateNameLookupTable(
45614555
// order.
45624556
SmallVector<DeclarationName, 16> Names;
45634557

4564-
// We also build up small sets of the constructor and conversion function
4565-
// names which are visible.
4566-
llvm::SmallPtrSet<DeclarationName, 8> ConstructorNameSet, ConversionNameSet;
4567-
4568-
for (auto &Lookup : *DC->buildLookup()) {
4569-
auto &Name = Lookup.first;
4570-
auto &Result = Lookup.second;
4558+
// We also track whether we're writing out the DeclarationNameKey for
4559+
// constructors or conversion functions.
4560+
bool IncludeConstructorNames = false;
4561+
bool IncludeConversionNames = false;
45714562

4563+
for (auto &[Name, Result] : *DC->buildLookup()) {
45724564
// If there are no local declarations in our lookup result, we
45734565
// don't need to write an entry for the name at all. If we can't
45744566
// write out a lookup set without performing more deserialization,
@@ -4577,15 +4569,8 @@ void ASTWriter::GenerateNameLookupTable(
45774569
// Also in reduced BMI, we'd like to avoid writing unreachable
45784570
// declarations in GMF, so we need to avoid writing declarations
45794571
// that entirely external or unreachable.
4580-
//
4581-
// FIMXE: It looks sufficient to test
4582-
// isLookupResultNotInteresting here. But due to bug we have
4583-
// to test isLookupResultExternal here. See
4584-
// https://github.com/llvm/llvm-project/issues/61065 for details.
4585-
if ((GeneratingReducedBMI || isLookupResultExternal(Result, DC)) &&
4586-
isLookupResultNotInteresting(*this, Result))
4572+
if (GeneratingReducedBMI && isLookupResultNotInteresting(*this, Result))
45874573
continue;
4588-
45894574
// We also skip empty results. If any of the results could be external and
45904575
// the currently available results are empty, then all of the results are
45914576
// external and we skip it above. So the only way we get here with an empty
@@ -4600,82 +4585,55 @@ void ASTWriter::GenerateNameLookupTable(
46004585
// results for them. This in almost certainly a bug in Clang's name lookup,
46014586
// but that is likely to be hard or impossible to fix and so we tolerate it
46024587
// here by omitting lookups with empty results.
4603-
if (Lookup.second.getLookupResult().empty())
4588+
if (Result.getLookupResult().empty())
46044589
continue;
46054590

4606-
switch (Lookup.first.getNameKind()) {
4591+
switch (Name.getNameKind()) {
46074592
default:
4608-
Names.push_back(Lookup.first);
4593+
Names.push_back(Name);
46094594
break;
46104595

46114596
case DeclarationName::CXXConstructorName:
4612-
assert(isa<CXXRecordDecl>(DC) &&
4613-
"Cannot have a constructor name outside of a class!");
4614-
ConstructorNameSet.insert(Name);
4597+
IncludeConstructorNames = true;
46154598
break;
46164599

46174600
case DeclarationName::CXXConversionFunctionName:
4618-
assert(isa<CXXRecordDecl>(DC) &&
4619-
"Cannot have a conversion function name outside of a class!");
4620-
ConversionNameSet.insert(Name);
4601+
IncludeConversionNames = true;
46214602
break;
46224603
}
46234604
}
46244605

46254606
// Sort the names into a stable order.
46264607
llvm::sort(Names);
46274608

4628-
if (auto *D = dyn_cast<CXXRecordDecl>(DC)) {
4609+
if (IncludeConstructorNames || IncludeConversionNames) {
46294610
// We need to establish an ordering of constructor and conversion function
4630-
// names, and they don't have an intrinsic ordering.
4631-
4632-
// First we try the easy case by forming the current context's constructor
4633-
// name and adding that name first. This is a very useful optimization to
4634-
// avoid walking the lexical declarations in many cases, and it also
4635-
// handles the only case where a constructor name can come from some other
4636-
// lexical context -- when that name is an implicit constructor merged from
4637-
// another declaration in the redecl chain. Any non-implicit constructor or
4638-
// conversion function which doesn't occur in all the lexical contexts
4639-
// would be an ODR violation.
4640-
auto ImplicitCtorName = Context.DeclarationNames.getCXXConstructorName(
4641-
Context.getCanonicalType(Context.getRecordType(D)));
4642-
if (ConstructorNameSet.erase(ImplicitCtorName))
4643-
Names.push_back(ImplicitCtorName);
4644-
4645-
// If we still have constructors or conversion functions, we walk all the
4646-
// names in the decl and add the constructors and conversion functions
4647-
// which are visible in the order they lexically occur within the context.
4648-
if (!ConstructorNameSet.empty() || !ConversionNameSet.empty())
4649-
for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls())
4650-
if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
4651-
auto Name = ChildND->getDeclName();
4652-
switch (Name.getNameKind()) {
4653-
default:
4654-
continue;
4655-
4656-
case DeclarationName::CXXConstructorName:
4657-
if (ConstructorNameSet.erase(Name))
4658-
Names.push_back(Name);
4659-
break;
4611+
// names, and they don't have an intrinsic ordering. We also need to write
4612+
// out all constructor and conversion function results if we write out any
4613+
// of them, because they're all tracked under the same lookup key.
4614+
llvm::SmallPtrSet<DeclarationName, 8> AddedNames;
4615+
for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls()) {
4616+
if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
4617+
auto Name = ChildND->getDeclName();
4618+
switch (Name.getNameKind()) {
4619+
default:
4620+
continue;
46604621

4661-
case DeclarationName::CXXConversionFunctionName:
4662-
if (ConversionNameSet.erase(Name))
4663-
Names.push_back(Name);
4664-
break;
4665-
}
4622+
case DeclarationName::CXXConstructorName:
4623+
if (!IncludeConstructorNames)
4624+
continue;
4625+
break;
46664626

4667-
if (ConstructorNameSet.empty() && ConversionNameSet.empty())
4668-
break;
4627+
case DeclarationName::CXXConversionFunctionName:
4628+
if (!IncludeConversionNames)
4629+
continue;
4630+
break;
46694631
}
4670-
4671-
assert(ConstructorNameSet.empty() && "Failed to find all of the visible "
4672-
"constructors by walking all the "
4673-
"lexical members of the context.");
4674-
assert(ConversionNameSet.empty() && "Failed to find all of the visible "
4675-
"conversion functions by walking all "
4676-
"the lexical members of the context.");
4632+
if (AddedNames.insert(Name).second)
4633+
Names.push_back(Name);
4634+
}
4635+
}
46774636
}
4678-
46794637
// Next we need to do a lookup with each name into this decl context to fully
46804638
// populate any results from external sources. We don't actually use the
46814639
// results of these lookups because we only want to use the results after all

clang/test/Modules/pr61065-2.cppm

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -fallow-pcm-with-compiler-errors -fmodule-name=c -xc++ -emit-module -fmodules -std=gnu++20 %t/a.cppmap -o %t/c.pcm
6+
//--- a.cppmap
7+
module "c" {
8+
header "a.h"
9+
}
10+
11+
//--- a.h
12+
template <class>
13+
class C {};
14+
template <class T>
15+
C<T>::operator C() {}

clang/test/Modules/pr61065-3.cppm

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang -std=c++20 -Wno-experimental-header-units -fmodule-header %t/RelaxedAtomic.h -o %t/RelaxedAtomic.pcm
6+
// RUN: %clang -std=c++20 -Wno-experimental-header-units -fmodule-header -fmodule-file=%t/RelaxedAtomic.pcm %t/SharedMutex.h -o %t/SharedMutex.pcm
7+
// RUN: %clang -std=c++20 -Wno-experimental-header-units -fmodule-header -fmodule-file=%t/SharedMutex.pcm -fmodule-file=%t/RelaxedAtomic.pcm %t/ThreadLocalDetail.h -o %t/ThreadLocalDetail.pcm
8+
//--- RelaxedAtomic.h
9+
struct relaxed_atomic_base {
10+
relaxed_atomic_base(int) {}
11+
};
12+
13+
struct relaxed_atomic : relaxed_atomic_base {
14+
using relaxed_atomic_base::relaxed_atomic_base; // constructor
15+
};
16+
17+
//--- SharedMutex.h
18+
import "RelaxedAtomic.h";
19+
20+
inline void getMaxDeferredReaders() {
21+
static relaxed_atomic cache{0};
22+
}
23+
24+
//--- ThreadLocalDetail.h
25+
import "RelaxedAtomic.h";
26+
27+
struct noncopyable {
28+
noncopyable(const noncopyable&) = delete;
29+
};
30+
31+
struct StaticMetaBase {
32+
relaxed_atomic nextId_{0};
33+
noncopyable ncp;
34+
};

clang/test/Modules/pr61065.cppm

Lines changed: 6 additions & 6 deletions
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-
// 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
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
1212

1313
// Test again with reduced BMI
1414
// RUN: rm -rf %t
@@ -18,9 +18,9 @@
1818
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-reduced-module-interface -o %t/a.pcm
1919
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-reduced-module-interface -o %t/b.pcm \
2020
// RUN: -fprebuilt-module-path=%t
21-
// DISABLED: %clang_cc1 -std=c++20 %t/c.cppm -emit-reduced-module-interface -o %t/c.pcm \
22-
// DISABLED: -fprebuilt-module-path=%t
23-
// DISABLED: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify -fprebuilt-module-path=%t
21+
// RUN: %clang_cc1 -std=c++20 %t/c.cppm -emit-reduced-module-interface -o %t/c.pcm \
22+
// RUN: -fprebuilt-module-path=%t
23+
// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fsyntax-only -verify -fprebuilt-module-path=%t
2424

2525

2626
//--- a.cppm

0 commit comments

Comments
 (0)