7
7
#include " clang/AST/GlobalDecl.h"
8
8
#include " clang/AST/Mangle.h"
9
9
#include " clang/Sema/Lookup.h"
10
+ #include " clang/Sema/Overload.h"
10
11
#include " clang/Sema/Sema.h"
11
12
#include " toolchain/check/call.h"
12
13
#include " toolchain/check/context.h"
20
21
21
22
namespace Carbon ::Check {
22
23
24
+ // Returns the GlobalDecl to use to represent the given function declaration.
25
+ // TODO: Refactor with `Lower::CreateGlobalDecl`.
26
+ static auto GetGlobalDecl (const clang::FunctionDecl* decl)
27
+ -> clang::GlobalDecl {
28
+ if (const auto * ctor = dyn_cast<clang::CXXConstructorDecl>(decl)) {
29
+ return clang::GlobalDecl (ctor, clang::CXXCtorType::Ctor_Complete);
30
+ }
31
+ return clang::GlobalDecl (decl);
32
+ }
33
+
23
34
// Returns the C++ thunk mangled name given the callee function.
24
35
static auto GenerateThunkMangledName (
25
36
clang::MangleContext& mangle_context,
26
37
const clang::FunctionDecl& callee_function_decl) -> std::string {
27
38
RawStringOstream mangled_name_stream;
28
- mangle_context.mangleName (clang::GlobalDecl (&callee_function_decl),
39
+ mangle_context.mangleName (GetGlobalDecl (&callee_function_decl),
29
40
mangled_name_stream);
30
41
mangled_name_stream << " .carbon_thunk" ;
31
42
@@ -74,12 +85,6 @@ auto IsCppThunkRequired(Context& context, const SemIR::Function& function)
74
85
return false ;
75
86
}
76
87
77
- if (isa<clang::CXXConstructorDecl>(
78
- context.sem_ir ().clang_decls ().Get (function.clang_decl_id ).decl )) {
79
- // TODO: Support generating thunks for constructors.
80
- return false ;
81
- }
82
-
83
88
// A thunk is required if any parameter or return type requires it. However,
84
89
// we don't generate a thunk if any relevant type is erroneous.
85
90
bool thunk_required = false ;
@@ -131,14 +136,18 @@ namespace {
131
136
// Information about the callee of a thunk.
132
137
struct CalleeFunctionInfo {
133
138
explicit CalleeFunctionInfo (clang::FunctionDecl* decl) : decl(decl) {
139
+ auto & ast_context = decl->getASTContext ();
134
140
const auto * method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
135
- has_object_parameter = method_decl && !method_decl-> isStatic () &&
136
- !isa<clang::CXXConstructorDecl>(method_decl) ;
141
+ bool is_ctor = isa<clang::CXXConstructorDecl>(decl);
142
+ has_object_parameter = method_decl && !method_decl-> isStatic () && !is_ctor ;
137
143
if (has_object_parameter && method_decl->isImplicitObjectMemberFunction ()) {
138
144
implicit_this_type = method_decl->getThisType ();
139
145
}
146
+ effective_return_type =
147
+ is_ctor ? ast_context.getRecordType (method_decl->getParent ())
148
+ : decl->getReturnType ();
140
149
has_simple_return_type =
141
- IsSimpleAbiType (decl-> getASTContext (), decl-> getReturnType () );
150
+ IsSimpleAbiType (ast_context, effective_return_type );
142
151
}
143
152
144
153
// Returns whether this callee has an implicit `this` parameter.
@@ -181,6 +190,11 @@ struct CalleeFunctionInfo {
181
190
// type. Otherwise a null type.
182
191
clang::QualType implicit_this_type;
183
192
193
+ // The return type that the callee has when viewed from Carbon. This is the
194
+ // C++ return type, except that constructors return the class type in Carbon
195
+ // and return void in Clang's AST.
196
+ clang::QualType effective_return_type;
197
+
184
198
// Whether the callee has a simple return type, that we can return directly.
185
199
// If not, we'll return through an out parameter instead.
186
200
bool has_simple_return_type;
@@ -228,7 +242,7 @@ static auto BuildThunkParameterTypes(clang::ASTContext& ast_context,
228
242
if (!callee_info.has_simple_return_type ) {
229
243
thunk_param_types.push_back (GetNonnullType (
230
244
ast_context,
231
- ast_context.getPointerType (callee_info.decl -> getReturnType () )));
245
+ ast_context.getPointerType (callee_info.effective_return_type )));
232
246
}
233
247
234
248
CARBON_CHECK (thunk_param_types.size () == callee_info.num_thunk_params ());
@@ -295,7 +309,7 @@ static auto CreateThunkFunctionDecl(
295
309
296
310
auto ext_proto_info = clang::FunctionProtoType::ExtProtoInfo ();
297
311
clang::QualType thunk_function_type = ast_context.getFunctionType (
298
- callee_info.has_simple_return_type ? callee_info.decl -> getReturnType ()
312
+ callee_info.has_simple_return_type ? callee_info.effective_return_type
299
313
: ast_context.VoidTy ,
300
314
thunk_param_types, ext_proto_info);
301
315
@@ -418,7 +432,7 @@ static auto BuildThunkBody(clang::Sema& sema,
418
432
/* HadMultipleCandidates=*/ false , clang::DeclarationNameInfo (),
419
433
sema.getASTContext ().BoundMemberTy , clang::VK_PRValue,
420
434
clang::OK_Ordinary);
421
- } else {
435
+ } else if (!isa<clang::CXXConstructorDecl>(callee_info. decl )) {
422
436
callee =
423
437
sema.BuildDeclRefExpr (callee_info.decl , callee_info.decl ->getType (),
424
438
clang::VK_PRValue, clang_loc);
@@ -432,8 +446,27 @@ static auto BuildThunkBody(clang::Sema& sema,
432
446
llvm::SmallVector<clang::Expr*> call_args =
433
447
BuildCalleeArgs (sema, thunk_function_decl, callee_info);
434
448
435
- clang::ExprResult call = sema.BuildCallExpr (nullptr , callee.get (), clang_loc,
436
- call_args, clang_loc);
449
+ clang::ExprResult call;
450
+ if (auto info = clang::getConstructorInfo (callee_info.decl );
451
+ info.Constructor ) {
452
+ // In C++, there are no direct calls to constructors, only initialization,
453
+ // so we need to type-check and build the call ourselves.
454
+ auto type = sema.Context .getRecordType (
455
+ cast<clang::CXXRecordDecl>(callee_info.decl ->getParent ()));
456
+ llvm::SmallVector<clang::Expr*> converted_args;
457
+ converted_args.reserve (call_args.size ());
458
+ if (sema.CompleteConstructorCall (info.Constructor , type, call_args,
459
+ clang_loc, converted_args)) {
460
+ return clang::StmtError ();
461
+ }
462
+ call = sema.BuildCXXConstructExpr (
463
+ clang_loc, type, callee_info.decl , info.Constructor , converted_args,
464
+ false , false , false , false , clang::CXXConstructionKind::Complete,
465
+ clang_loc);
466
+ } else {
467
+ call = sema.BuildCallExpr (nullptr , callee.get (), clang_loc, call_args,
468
+ clang_loc);
469
+ }
437
470
if (!call.isUsable ()) {
438
471
return clang::StmtError ();
439
472
}
@@ -444,7 +477,7 @@ static auto BuildThunkBody(clang::Sema& sema,
444
477
445
478
auto * return_object_addr = BuildThunkParamRef (
446
479
sema, thunk_function_decl, callee_info.GetThunkReturnParamIndex ());
447
- auto return_type = callee_info.decl -> getReturnType () ;
480
+ auto return_type = callee_info.effective_return_type ;
448
481
auto * return_type_info =
449
482
sema.Context .getTrivialTypeSourceInfo (return_type, clang_loc);
450
483
auto placement_new = sema.BuildCXXNew (
0 commit comments