mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 21:11:27 +01:00
Basic support for calling class methods imported from C++. (#5796)
Create a `self` parameter when importing a C++ non-static member function. That seems to be all we need to get basic method calls working! For now, `const` methods have by-value self parameters, and non-`const` methods get an `addr self: Self*` parameter.
This commit is contained in:
+102
-12
@@ -27,6 +27,7 @@
|
||||
#include "toolchain/check/convert.h"
|
||||
#include "toolchain/check/diagnostic_helpers.h"
|
||||
#include "toolchain/check/eval.h"
|
||||
#include "toolchain/check/function.h"
|
||||
#include "toolchain/check/import.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/literal.h"
|
||||
@@ -805,6 +806,87 @@ static auto MapType(Context& context, SemIR::LocId loc_id, clang::QualType type)
|
||||
return mapped;
|
||||
}
|
||||
|
||||
// Returns a block for the implicit parameters of the given function
|
||||
// declaration. Because function templates are not yet supported, this currently
|
||||
// only contains the `self` parameter. On error, produces a diagnostic and
|
||||
// returns None.
|
||||
static auto MakeImplicitParamPatternsBlockId(
|
||||
Context& context, SemIR::LocId loc_id,
|
||||
const clang::FunctionDecl& clang_decl) -> SemIR::InstBlockId {
|
||||
const auto* method_decl = dyn_cast<clang::CXXMethodDecl>(&clang_decl);
|
||||
if (!method_decl || method_decl->isStatic()) {
|
||||
return SemIR::InstBlockId::Empty;
|
||||
}
|
||||
|
||||
// Build a `self` parameter from the object parameter.
|
||||
BeginSubpattern(context);
|
||||
|
||||
// Perform some special-case mapping for the object parameter:
|
||||
//
|
||||
// - If it's a const reference to T, produce a by-value `self: T` parameter.
|
||||
// - If it's a non-const reference to T, produce an `addr self: T*`
|
||||
// parameter.
|
||||
// - Otherwise, map it directly, which will currently fail for `&&`-qualified
|
||||
// methods.
|
||||
//
|
||||
// TODO: Some of this mapping should be performed for all parameters.
|
||||
clang::QualType param_type =
|
||||
method_decl->getFunctionObjectParameterReferenceType();
|
||||
bool addr_self = false;
|
||||
if (param_type->isLValueReferenceType()) {
|
||||
param_type = param_type.getNonReferenceType();
|
||||
if (param_type.isConstQualified()) {
|
||||
// TODO: Consider only doing this if `const` is the only qualifier. For
|
||||
// now, any other qualifier will fail when mapping the type.
|
||||
auto split_type = param_type.getSplitUnqualifiedType();
|
||||
split_type.Quals.removeConst();
|
||||
param_type = method_decl->getASTContext().getQualifiedType(split_type);
|
||||
} else {
|
||||
addr_self = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto [type_inst_id, type_id] = MapType(context, loc_id, param_type);
|
||||
SemIR::ExprRegionId type_expr_region_id =
|
||||
EndSubpatternAsExpr(context, type_inst_id);
|
||||
|
||||
if (!type_id.has_value()) {
|
||||
context.TODO(loc_id,
|
||||
llvm::formatv("Unsupported: object parameter type: {0}",
|
||||
param_type.getAsString()));
|
||||
return SemIR::InstBlockId::None;
|
||||
}
|
||||
|
||||
if (addr_self) {
|
||||
type_id = GetPointerType(context, type_inst_id);
|
||||
}
|
||||
|
||||
SemIR::InstId pattern_id =
|
||||
// TODO: Fill in a location once available.
|
||||
AddBindingPattern(context, SemIR::LocId::None, SemIR::NameId::SelfValue,
|
||||
type_id, type_expr_region_id, /*is_generic*/ false,
|
||||
/*is_template*/ false)
|
||||
.pattern_id;
|
||||
|
||||
// TODO: Fill in a location once available.
|
||||
pattern_id = AddPatternInst<SemIR::ValueParamPattern>(
|
||||
context, SemIR::LocId::None,
|
||||
{.type_id = context.insts().Get(pattern_id).type_id(),
|
||||
.subpattern_id = pattern_id,
|
||||
.index = SemIR::CallParamIndex::None});
|
||||
|
||||
// If we're building `addr self: Self*`, do that now.
|
||||
if (addr_self) {
|
||||
// TODO: Fill in a location once available.
|
||||
pattern_id = AddPatternInst<SemIR::AddrPattern>(
|
||||
context, SemIR::LocId::None,
|
||||
{.type_id = GetPatternType(context, SemIR::AutoType::TypeId),
|
||||
.inner_id = pattern_id});
|
||||
}
|
||||
|
||||
return context.inst_blocks().Add({pattern_id});
|
||||
}
|
||||
|
||||
// Returns a block id for the explicit parameters of the given function
|
||||
// declaration. If the function declaration has no parameters, it returns
|
||||
// `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it
|
||||
@@ -909,6 +991,7 @@ namespace {
|
||||
// Represents the parameter patterns block id, the return slot pattern id and
|
||||
// the call parameters block id for a function declaration.
|
||||
struct FunctionParamsInsts {
|
||||
SemIR::InstBlockId implicit_param_patterns_id;
|
||||
SemIR::InstBlockId param_patterns_id;
|
||||
SemIR::InstId return_slot_pattern_id;
|
||||
SemIR::InstBlockId call_params_id;
|
||||
@@ -927,6 +1010,16 @@ struct FunctionParamsInsts {
|
||||
static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id,
|
||||
const clang::FunctionDecl* clang_decl)
|
||||
-> std::optional<FunctionParamsInsts> {
|
||||
if (isa<clang::CXXConstructorDecl, clang::CXXDestructorDecl>(clang_decl)) {
|
||||
context.TODO(loc_id, "Unsupported: Constructor/Destructor");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto implicit_param_patterns_id =
|
||||
MakeImplicitParamPatternsBlockId(context, loc_id, *clang_decl);
|
||||
if (!implicit_param_patterns_id.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto param_patterns_id =
|
||||
MakeParamPatternsBlockId(context, loc_id, *clang_decl);
|
||||
if (!param_patterns_id.has_value()) {
|
||||
@@ -937,12 +1030,12 @@ static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id,
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// TODO: Add support for implicit parameters.
|
||||
auto call_params_id = CalleePatternMatch(
|
||||
context, /*implicit_param_patterns_id=*/SemIR::InstBlockId::None,
|
||||
param_patterns_id, return_slot_pattern_id);
|
||||
auto call_params_id =
|
||||
CalleePatternMatch(context, implicit_param_patterns_id, param_patterns_id,
|
||||
return_slot_pattern_id);
|
||||
|
||||
return {{.param_patterns_id = param_patterns_id,
|
||||
return {{.implicit_param_patterns_id = implicit_param_patterns_id,
|
||||
.param_patterns_id = param_patterns_id,
|
||||
.return_slot_pattern_id = return_slot_pattern_id,
|
||||
.call_params_id = call_params_id}};
|
||||
}
|
||||
@@ -959,11 +1052,6 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
MarkFailedDecl(context, clang_decl);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
if (!clang_decl->isGlobal()) {
|
||||
context.TODO(loc_id, "Unsupported: Non-global function");
|
||||
MarkFailedDecl(context, clang_decl);
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
if (clang_decl->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate) {
|
||||
context.TODO(loc_id, "Unsupported: Template function");
|
||||
MarkFailedDecl(context, clang_decl);
|
||||
@@ -999,7 +1087,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
.first_param_node_id = Parse::NodeId::None,
|
||||
.last_param_node_id = Parse::NodeId::None,
|
||||
.pattern_block_id = pattern_block_id,
|
||||
.implicit_param_patterns_id = SemIR::InstBlockId::Empty,
|
||||
.implicit_param_patterns_id =
|
||||
function_params_insts->implicit_param_patterns_id,
|
||||
.param_patterns_id = function_params_insts->param_patterns_id,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
@@ -1009,7 +1098,8 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
{.call_params_id = function_params_insts->call_params_id,
|
||||
.return_slot_pattern_id = function_params_insts->return_slot_pattern_id,
|
||||
.virtual_modifier = SemIR::FunctionFields::VirtualModifier::None,
|
||||
.self_param_id = SemIR::InstId::None,
|
||||
.self_param_id = FindSelfPattern(
|
||||
context, function_params_insts->implicit_param_patterns_id),
|
||||
.clang_decl_id = context.sem_ir().clang_decls().Add(
|
||||
{.decl = clang_decl, .inst_id = decl_id})}};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user