Skip to content

Commit 55cdb3c

Browse files
authored
[C++20] [Modules] Merge lambdas in source to imported lambdas (#106483)
Close #102721 Generally, the type of merged decls will be reused in ASTContext. But for lambda, in the import and then include case, we can't decide its previous decl in the imported modules so that we can't assign the previous decl before creating the type for it. Since we can't decide its numbering before creating it. So we have to assign the previous decl and the canonical type for it after creating it, which is unusual and slightly hack.
1 parent 8bf69ce commit 55cdb3c

File tree

8 files changed

+66
-12
lines changed

8 files changed

+66
-12
lines changed

clang/include/clang/AST/Decl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3366,6 +3366,7 @@ class IndirectFieldDecl : public ValueDecl,
33663366
/// Represents a declaration of a type.
33673367
class TypeDecl : public NamedDecl {
33683368
friend class ASTContext;
3369+
friend class ASTReader;
33693370

33703371
/// This indicates the Type object that represents
33713372
/// this TypeDecl. It is a cache maintained by

clang/include/clang/AST/Type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,7 @@ class ExtQualsTypeCommonBase {
16841684
friend class ExtQuals;
16851685
friend class QualType;
16861686
friend class Type;
1687+
friend class ASTReader;
16871688

16881689
/// The "base" type of an extended qualifiers type (\c ExtQuals) or
16891690
/// a self-referential pointer (for \c Type).

clang/include/clang/Sema/ExternalSemaSource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ class ExternalSemaSource : public ExternalASTSource {
233233
/// Notify the external source that a lambda was assigned a mangling number.
234234
/// This enables the external source to track the correspondence between
235235
/// lambdas and mangling numbers if necessary.
236-
virtual void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) {}
236+
virtual void AssignedLambdaNumbering(CXXRecordDecl *Lambda) {}
237237

238238
/// LLVM-style RTTI.
239239
/// \{

clang/include/clang/Sema/MultiplexExternalSemaSource.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ class MultiplexExternalSemaSource : public ExternalSemaSource {
361361
QualType T) override;
362362

363363
// Inform all attached sources that a mangling number was assigned.
364-
void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) override;
364+
void AssignedLambdaNumbering(CXXRecordDecl *Lambda) override;
365365

366366
/// LLVM-style RTTI.
367367
/// \{

clang/include/clang/Serialization/ASTReader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2149,7 +2149,7 @@ class ASTReader
21492149
llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>>
21502150
&LPTMap) override;
21512151

2152-
void AssignedLambdaNumbering(const CXXRecordDecl *Lambda) override;
2152+
void AssignedLambdaNumbering(CXXRecordDecl *Lambda) override;
21532153

21542154
/// Load a selector from disk, registering its ID if it exists.
21552155
void LoadSelector(Selector Sel);

clang/lib/Sema/MultiplexExternalSemaSource.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ bool MultiplexExternalSemaSource::MaybeDiagnoseMissingCompleteType(
343343
}
344344

345345
void MultiplexExternalSemaSource::AssignedLambdaNumbering(
346-
const CXXRecordDecl *Lambda) {
346+
CXXRecordDecl *Lambda) {
347347
for (auto *Source : Sources)
348348
Source->AssignedLambdaNumbering(Lambda);
349349
}

clang/lib/Serialization/ASTReader.cpp

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8963,15 +8963,34 @@ void ASTReader::ReadLateParsedTemplates(
89638963
LateParsedTemplates.clear();
89648964
}
89658965

8966-
void ASTReader::AssignedLambdaNumbering(const CXXRecordDecl *Lambda) {
8967-
if (Lambda->getLambdaContextDecl()) {
8968-
// Keep track of this lambda so it can be merged with another lambda that
8969-
// is loaded later.
8970-
LambdaDeclarationsForMerging.insert(
8971-
{{Lambda->getLambdaContextDecl()->getCanonicalDecl(),
8972-
Lambda->getLambdaIndexInContext()},
8973-
const_cast<CXXRecordDecl *>(Lambda)});
8966+
void ASTReader::AssignedLambdaNumbering(CXXRecordDecl *Lambda) {
8967+
if (!Lambda->getLambdaContextDecl())
8968+
return;
8969+
8970+
auto LambdaInfo =
8971+
std::make_pair(Lambda->getLambdaContextDecl()->getCanonicalDecl(),
8972+
Lambda->getLambdaIndexInContext());
8973+
8974+
// Handle the import and then include case for lambdas.
8975+
if (auto Iter = LambdaDeclarationsForMerging.find(LambdaInfo);
8976+
Iter != LambdaDeclarationsForMerging.end() &&
8977+
Iter->second->isFromASTFile() && Lambda->getFirstDecl() == Lambda) {
8978+
CXXRecordDecl *Previous =
8979+
cast<CXXRecordDecl>(Iter->second)->getMostRecentDecl();
8980+
Lambda->setPreviousDecl(Previous);
8981+
// FIXME: It will be best to use the Previous type when we creating the
8982+
// lambda directly. But that requires us to get the lambda context decl and
8983+
// lambda index before creating the lambda, which needs a drastic change in
8984+
// the parser.
8985+
const_cast<QualType &>(Lambda->TypeForDecl->CanonicalType) =
8986+
Previous->TypeForDecl->CanonicalType;
8987+
return;
89748988
}
8989+
8990+
// Keep track of this lambda so it can be merged with another lambda that
8991+
// is loaded later.
8992+
LambdaDeclarationsForMerging.insert(
8993+
{LambdaInfo, const_cast<CXXRecordDecl *>(Lambda)});
89758994
}
89768995

89778996
void ASTReader::LoadSelector(Selector Sel) {

clang/test/Modules/pr102721.cppm

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: rm -rf %t
2+
// RUN: mkdir -p %t
3+
// RUN: split-file %s %t
4+
//
5+
// RUN: %clang_cc1 -std=c++20 %t/a.cppm -emit-module-interface -o %t/a.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/b.cppm -emit-module-interface -o %t/b.pcm \
7+
// RUN: -fprebuilt-module-path=%t
8+
// RUN: %clang_cc1 -std=c++20 %t/test.cc -fsyntax-only -verify \
9+
// RUN: -fprebuilt-module-path=%t
10+
11+
//--- foo.h
12+
inline auto x = []{};
13+
14+
//--- a.cppm
15+
module;
16+
#include "foo.h"
17+
export module a;
18+
export using ::x;
19+
20+
//--- b.cppm
21+
module;
22+
import a;
23+
#include "foo.h"
24+
export module b;
25+
export using ::x;
26+
27+
//--- test.cc
28+
// expected-no-diagnostics
29+
import a;
30+
import b;
31+
void test() {
32+
x();
33+
}

0 commit comments

Comments
 (0)