Skip to content

Commit b41a79e

Browse files
authored
Merge pull request #7709 from apple/egorzhdan/std-optional-serialization-20230725
🍒[Clang] Fix compiler crash while serializing `std::optional`
2 parents 4ab3b70 + ab3ed65 commit b41a79e

File tree

3 files changed

+38
-73
lines changed

3 files changed

+38
-73
lines changed

clang/include/clang/Serialization/ASTWriter.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,6 @@ class ASTWriter : public ASTDeserializationListener,
524524
void WriteTypeAbbrevs();
525525
void WriteType(QualType T);
526526

527-
bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC);
528527
bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC);
529528

530529
void GenerateNameLookupTable(const DeclContext *DC,

clang/lib/Serialization/ASTWriter.cpp

Lines changed: 35 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3940,12 +3940,6 @@ class ASTDeclContextNameLookupTrait {
39403940

39413941
} // namespace
39423942

3943-
bool ASTWriter::isLookupResultExternal(StoredDeclsList &Result,
3944-
DeclContext *DC) {
3945-
return Result.hasExternalDecls() &&
3946-
DC->hasNeedToReconcileExternalVisibleStorage();
3947-
}
3948-
39493943
bool ASTWriter::isLookupResultEntirelyExternal(StoredDeclsList &Result,
39503944
DeclContext *DC) {
39513945
for (auto *D : Result.getLookupResult())
@@ -3976,20 +3970,17 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
39763970
// order.
39773971
SmallVector<DeclarationName, 16> Names;
39783972

3979-
// We also build up small sets of the constructor and conversion function
3980-
// names which are visible.
3981-
llvm::SmallPtrSet<DeclarationName, 8> ConstructorNameSet, ConversionNameSet;
3982-
3983-
for (auto &Lookup : *DC->buildLookup()) {
3984-
auto &Name = Lookup.first;
3985-
auto &Result = Lookup.second;
3973+
// We also track whether we're writing out the DeclarationNameKey for
3974+
// constructors or conversion functions.
3975+
bool IncludeConstructorNames = false;
3976+
bool IncludeConversionNames = false;
39863977

3978+
for (auto &[Name, Result] : *DC->buildLookup()) {
39873979
// If there are no local declarations in our lookup result, we
39883980
// don't need to write an entry for the name at all. If we can't
39893981
// write out a lookup set without performing more deserialization,
39903982
// just skip this entry.
3991-
if (isLookupResultExternal(Result, DC) &&
3992-
isLookupResultEntirelyExternal(Result, DC))
3983+
if (isLookupResultEntirelyExternal(Result, DC))
39933984
continue;
39943985

39953986
// We also skip empty results. If any of the results could be external and
@@ -4006,80 +3997,55 @@ ASTWriter::GenerateNameLookupTable(const DeclContext *ConstDC,
40063997
// results for them. This in almost certainly a bug in Clang's name lookup,
40073998
// but that is likely to be hard or impossible to fix and so we tolerate it
40083999
// here by omitting lookups with empty results.
4009-
if (Lookup.second.getLookupResult().empty())
4000+
if (Result.getLookupResult().empty())
40104001
continue;
40114002

4012-
switch (Lookup.first.getNameKind()) {
4003+
switch (Name.getNameKind()) {
40134004
default:
4014-
Names.push_back(Lookup.first);
4005+
Names.push_back(Name);
40154006
break;
40164007

40174008
case DeclarationName::CXXConstructorName:
4018-
assert(isa<CXXRecordDecl>(DC) &&
4019-
"Cannot have a constructor name outside of a class!");
4020-
ConstructorNameSet.insert(Name);
4009+
IncludeConstructorNames = true;
40214010
break;
40224011

40234012
case DeclarationName::CXXConversionFunctionName:
4024-
assert(isa<CXXRecordDecl>(DC) &&
4025-
"Cannot have a conversion function name outside of a class!");
4026-
ConversionNameSet.insert(Name);
4013+
IncludeConversionNames = true;
40274014
break;
40284015
}
40294016
}
40304017

40314018
// Sort the names into a stable order.
40324019
llvm::sort(Names);
40334020

4034-
if (auto *D = dyn_cast<CXXRecordDecl>(DC)) {
4021+
if (IncludeConstructorNames || IncludeConversionNames) {
40354022
// We need to establish an ordering of constructor and conversion function
4036-
// names, and they don't have an intrinsic ordering.
4037-
4038-
// First we try the easy case by forming the current context's constructor
4039-
// name and adding that name first. This is a very useful optimization to
4040-
// avoid walking the lexical declarations in many cases, and it also
4041-
// handles the only case where a constructor name can come from some other
4042-
// lexical context -- when that name is an implicit constructor merged from
4043-
// another declaration in the redecl chain. Any non-implicit constructor or
4044-
// conversion function which doesn't occur in all the lexical contexts
4045-
// would be an ODR violation.
4046-
auto ImplicitCtorName = Context->DeclarationNames.getCXXConstructorName(
4047-
Context->getCanonicalType(Context->getRecordType(D)));
4048-
if (ConstructorNameSet.erase(ImplicitCtorName))
4049-
Names.push_back(ImplicitCtorName);
4050-
4051-
// If we still have constructors or conversion functions, we walk all the
4052-
// names in the decl and add the constructors and conversion functions
4053-
// which are visible in the order they lexically occur within the context.
4054-
if (!ConstructorNameSet.empty() || !ConversionNameSet.empty())
4055-
for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls())
4056-
if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
4057-
auto Name = ChildND->getDeclName();
4058-
switch (Name.getNameKind()) {
4059-
default:
4060-
continue;
4061-
4062-
case DeclarationName::CXXConstructorName:
4063-
if (ConstructorNameSet.erase(Name))
4064-
Names.push_back(Name);
4065-
break;
4023+
// names, and they don't have an intrinsic ordering. We also need to write
4024+
// out all constructor and conversion function results if we write out any
4025+
// of them, because they're all tracked under the same lookup key.
4026+
llvm::SmallPtrSet<DeclarationName, 8> AddedNames;
4027+
for (Decl *ChildD : cast<CXXRecordDecl>(DC)->decls()) {
4028+
if (auto *ChildND = dyn_cast<NamedDecl>(ChildD)) {
4029+
auto Name = ChildND->getDeclName();
4030+
switch (Name.getNameKind()) {
4031+
default:
4032+
continue;
40664033

4067-
case DeclarationName::CXXConversionFunctionName:
4068-
if (ConversionNameSet.erase(Name))
4069-
Names.push_back(Name);
4070-
break;
4071-
}
4034+
case DeclarationName::CXXConstructorName:
4035+
if (!IncludeConstructorNames)
4036+
continue;
4037+
break;
40724038

4073-
if (ConstructorNameSet.empty() && ConversionNameSet.empty())
4074-
break;
4039+
case DeclarationName::CXXConversionFunctionName:
4040+
if (!IncludeConversionNames)
4041+
continue;
4042+
break;
40754043
}
4076-
4077-
assert(ConstructorNameSet.empty() && "Failed to find all of the visible "
4078-
"constructors by walking all the "
4079-
"lexical members of the context.");
4080-
assert(ConversionNameSet.empty() && "Failed to find all of the visible "
4081-
"conversion functions by walking all "
4082-
"the lexical members of the context.");
4044+
// We should include lookup results for this name.
4045+
if (AddedNames.insert(Name).second)
4046+
Names.push_back(Name);
4047+
}
4048+
}
40834049
}
40844050

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

clang/test/Modules/pr61065.cppm

Lines changed: 3 additions & 3 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
//--- a.cppm
1414
export module a;

0 commit comments

Comments
 (0)