Skip to content

Commit bf9ab0b

Browse files
committed
[C++20] [Modules] Emit implicit Deduction Guide for implicit class specialization
Fixed a crash for the attached test case due to we missed to emit the deduction guide. The reason is, the deduction guide is attached to the export-decl in the imported module. So we won't emit it by traversing the AST of the current TU.
1 parent a522516 commit bf9ab0b

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

clang/lib/Serialization/ASTWriterDecl.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,6 +1785,18 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl(
17851785
if (ArgsWritten)
17861786
Record.AddASTTemplateArgumentListInfo(ArgsWritten);
17871787

1788+
// Mention the implicitly generated C++ deduction guide to make sure the
1789+
// deduction guide will be rewritten as expected.
1790+
//
1791+
// FIXME: Would it be more efficient to add a callback register function
1792+
// in sema to register the deduction guide?
1793+
if (Writer.isWritingStdCXXNamedModules()) {
1794+
auto Name = Context.DeclarationNames.getCXXDeductionGuideName(
1795+
D->getSpecializedTemplate());
1796+
for (auto *DG : D->getDeclContext()->noload_lookup(Name))
1797+
Writer.GetDeclRef(DG->getCanonicalDecl());
1798+
}
1799+
17881800
Code = serialization::DECL_CLASS_TEMPLATE_SPECIALIZATION;
17891801
}
17901802

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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/invocable.cppm -emit-module-interface -o %t/invocable.pcm
6+
// RUN: %clang_cc1 -std=c++20 %t/lambda.cppm -emit-module-interface -o %t/lambda.pcm -fprebuilt-module-path=%t
7+
// RUN: %clang_cc1 -std=c++20 %t/test.cc -fprebuilt-module-path=%t -fsyntax-only -verify
8+
//
9+
// RUN: %clang_cc1 -std=c++20 %t/invocable.cppm -emit-reduced-module-interface -o %t/invocable.pcm
10+
// RUN: %clang_cc1 -std=c++20 %t/lambda.cppm -emit-reduced-module-interface -o %t/lambda.pcm -fprebuilt-module-path=%t
11+
// RUN: %clang_cc1 -std=c++20 %t/test.cc -fprebuilt-module-path=%t -fsyntax-only -verify
12+
13+
//--- invocable.cppm
14+
export module invocable;
15+
export template <class _Fn, class... _Args>
16+
concept invocable = requires(_Fn&& __fn, _Args&&... __args) {
17+
_Fn(__args...);
18+
};
19+
20+
export template <class _Fn, class _Args>
21+
constexpr bool is_callable(_Fn&& __fn, _Args&& __args) {
22+
return invocable<_Fn, _Args>;
23+
}
24+
25+
export template <class _Fn>
26+
struct Callable : _Fn {
27+
constexpr explicit Callable(_Fn &&__fn) : _Fn(static_cast<_Fn&&>(__fn)) {}
28+
29+
template <class _Args>
30+
constexpr auto operator()(_Args&& __args) {
31+
return _Fn(__args);
32+
}
33+
};
34+
35+
//--- lambda.cppm
36+
export module lambda;
37+
import invocable;
38+
export constexpr auto l = Callable([](auto &&x){});
39+
40+
//--- test.cc
41+
// expected-no-diagnostics
42+
import invocable;
43+
import lambda;
44+
45+
static_assert(is_callable(l, 4) == true);

0 commit comments

Comments
 (0)