Skip to content

Commit aa7f856

Browse files
committed
When using a C++ struct as a parameter, map it to a Carbon type
This doesn't support actually passing the value of the struct, which is planned to be implemented using thunks. I plan to add more tests in a separate PR. Based on carbon-language#5534 and carbon-language#5537. Part of carbon-language#5533.
1 parent b1ace75 commit aa7f856

File tree

2 files changed

+375
-23
lines changed

2 files changed

+375
-23
lines changed

toolchain/check/import_cpp.cpp

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "toolchain/check/import.h"
2626
#include "toolchain/check/inst.h"
2727
#include "toolchain/check/literal.h"
28+
#include "toolchain/check/name_lookup.h"
2829
#include "toolchain/check/type.h"
2930
#include "toolchain/check/type_completion.h"
3031
#include "toolchain/diagnostics/diagnostic.h"
@@ -321,23 +322,19 @@ static auto MakeIntType(Context& context, IntId size_id) -> TypeExpr {
321322
return ExprAsType(context, Parse::NodeId::None, type_inst_id);
322323
}
323324

324-
// Maps a C++ type to a Carbon type.
325-
// TODO: Support more types.
326-
static auto MapType(Context& context, clang::QualType type) -> TypeExpr {
327-
const auto* builtin_type = dyn_cast<clang::BuiltinType>(type);
328-
if (!builtin_type) {
329-
return {.inst_id = SemIR::ErrorInst::TypeInstId,
330-
.type_id = SemIR::ErrorInst::TypeId};
331-
}
325+
// Maps a C++ builtin type to a Carbon type.
326+
// TODO: Support more builtin types.
327+
static auto MapBuiltinType(Context& context, const clang::BuiltinType& type)
328+
-> TypeExpr {
332329
// TODO: Refactor to avoid duplication.
333-
switch (builtin_type->getKind()) {
330+
switch (type.getKind()) {
334331
case clang::BuiltinType::Short:
335-
if (context.ast_context().getTypeSize(type) == 16) {
332+
if (context.ast_context().getTypeSize(&type) == 16) {
336333
return MakeIntType(context, context.ints().Add(16));
337334
}
338335
break;
339336
case clang::BuiltinType::Int:
340-
if (context.ast_context().getTypeSize(type) == 32) {
337+
if (context.ast_context().getTypeSize(&type) == 32) {
341338
return MakeIntType(context, context.ints().Add(32));
342339
}
343340
break;
@@ -348,11 +345,60 @@ static auto MapType(Context& context, clang::QualType type) -> TypeExpr {
348345
.type_id = SemIR::ErrorInst::TypeId};
349346
}
350347

348+
// Maps a C++ record type to a Carbon type.
349+
// TODO: Support more record types.
350+
static auto MapRecordType(Context& context, SemIR::LocId loc_id,
351+
SemIR::NameScopeId scope_id,
352+
const clang::RecordType& type) -> TypeExpr {
353+
const clang::RecordDecl* record_decl = type.getDecl();
354+
if (record_decl && record_decl->isStruct()) {
355+
LookupResult result = LookupQualifiedName(
356+
context, loc_id,
357+
SemIR::NameId::ForIdentifier(
358+
context.identifiers().Add(record_decl->getName())),
359+
LookupScope{.name_scope_id = scope_id,
360+
.specific_id = SemIR::SpecificId::None});
361+
if (result.scope_result.is_found()) {
362+
SemIR::InstId inst_id = result.scope_result.target_inst_id();
363+
if (inst_id != SemIR::ErrorInst::InstId) {
364+
return {.inst_id = context.types().GetAsTypeInstId(inst_id),
365+
.type_id = context.classes()
366+
.Get(context.insts()
367+
.Get(inst_id)
368+
.As<SemIR::ClassDecl>()
369+
.class_id)
370+
.self_type_id};
371+
}
372+
}
373+
}
374+
375+
return {.inst_id = SemIR::ErrorInst::TypeInstId,
376+
.type_id = SemIR::ErrorInst::TypeId};
377+
}
378+
379+
// Maps a C++ type to a Carbon type.
380+
// TODO: Support more types.
381+
static auto MapType(Context& context, SemIR::LocId loc_id,
382+
SemIR::NameScopeId scope_id, clang::QualType type)
383+
-> TypeExpr {
384+
if (const auto* builtin_type = dyn_cast<clang::BuiltinType>(type)) {
385+
return MapBuiltinType(context, *builtin_type);
386+
}
387+
388+
if (const auto* record_type = clang::dyn_cast<clang::RecordType>(type)) {
389+
return MapRecordType(context, loc_id, scope_id, *record_type);
390+
}
391+
392+
return {.inst_id = SemIR::ErrorInst::TypeInstId,
393+
.type_id = SemIR::ErrorInst::TypeId};
394+
}
395+
351396
// Returns a block id for the explicit parameters of the given function
352397
// declaration. If the function declaration has no parameters, it returns
353398
// `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it
354399
// returns `SemIR::InstBlockId::None`.
355400
static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
401+
SemIR::NameScopeId scope_id,
356402
const clang::FunctionDecl& clang_decl)
357403
-> SemIR::InstBlockId {
358404
if (clang_decl.parameters().empty()) {
@@ -363,8 +409,8 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
363409
params.reserve(clang_decl.parameters().size());
364410
for (const clang::ParmVarDecl* param : clang_decl.parameters()) {
365411
clang::QualType param_type = param->getType().getCanonicalType();
366-
SemIR::TypeId type_id =
367-
GetPatternType(context, MapType(context, param_type).type_id);
412+
SemIR::TypeId type_id = GetPatternType(
413+
context, MapType(context, loc_id, scope_id, param_type).type_id);
368414
if (type_id == SemIR::ErrorInst::TypeId) {
369415
context.TODO(loc_id, llvm::formatv("Unsupported: parameter type: {0}",
370416
param_type.getAsString()));
@@ -401,18 +447,26 @@ static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
401447
// Currently only void and 32-bit int are supported.
402448
// TODO: Support more return types.
403449
static auto GetReturnType(Context& context, SemIR::LocId loc_id,
450+
SemIR::NameScopeId scope_id,
404451
const clang::FunctionDecl* clang_decl)
405452
-> SemIR::InstId {
406453
clang::QualType ret_type = clang_decl->getReturnType().getCanonicalType();
407454
if (ret_type->isVoidType()) {
408455
return SemIR::InstId::None;
409456
}
410-
auto [type_inst_id, type_id] = MapType(context, ret_type);
457+
auto [type_inst_id, type_id] = MapType(context, loc_id, scope_id, ret_type);
411458
if (type_id == SemIR::ErrorInst::TypeId) {
412459
context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
413460
ret_type.getAsString()));
414461
return SemIR::ErrorInst::InstId;
415462
}
463+
if (SemIR::InitRepr::ForType(context.sem_ir(), type_id).kind ==
464+
SemIR::InitRepr::InPlace) {
465+
context.TODO(loc_id, llvm::formatv("Unsupported: in place return type: {0}",
466+
ret_type.getAsString()));
467+
return SemIR::ErrorInst::InstId;
468+
}
469+
416470
auto pattern_type_id = GetPatternType(context, type_id);
417471
SemIR::InstId return_slot_pattern_id = AddInstInNoBlock(
418472
// TODO: Fill in a location for the return type once available.
@@ -448,11 +502,12 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
448502
return SemIR::ErrorInst::InstId;
449503
}
450504
auto param_patterns_id =
451-
MakeParamPatternsBlockId(context, loc_id, *clang_decl);
505+
MakeParamPatternsBlockId(context, loc_id, scope_id, *clang_decl);
452506
if (!param_patterns_id.has_value()) {
453507
return SemIR::ErrorInst::InstId;
454508
}
455-
auto return_slot_pattern_id = GetReturnType(context, loc_id, clang_decl);
509+
auto return_slot_pattern_id =
510+
GetReturnType(context, loc_id, scope_id, clang_decl);
456511
if (SemIR::ErrorInst::InstId == return_slot_pattern_id) {
457512
return SemIR::ErrorInst::InstId;
458513
}

0 commit comments

Comments
 (0)