mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 21:11:27 +01:00
Support for mapping array types to/from C++. (#7285)
For now, disable the use of array types as by-var paramters and by-init return types when exporting Carbon functions to C++, as C++ does not support raw arrays being passed or returned by value. Assisted-by: Gemini via Antigravity
This commit is contained in:
@@ -343,13 +343,13 @@ struct FunctionInfo {
|
||||
Param(Context& context, SemIR::InstId param_inst_id)
|
||||
: type_id(ExtractScrutineeType(
|
||||
context.sem_ir(), context.insts().Get(param_inst_id).type_id())),
|
||||
is_ref(context.insts().Is<SemIR::RefParamPattern>(param_inst_id)) {}
|
||||
kind(GetParamPatternKind(context, param_inst_id)) {}
|
||||
|
||||
// Type of the parameter's scrutinee.
|
||||
SemIR::TypeId type_id;
|
||||
|
||||
// Whether this is a `ref` param.
|
||||
bool is_ref;
|
||||
// Kind of the parameter pattern.
|
||||
ParamPatternKind kind;
|
||||
};
|
||||
|
||||
explicit FunctionInfo(Context& context, SemIR::FunctionId function_id,
|
||||
@@ -416,6 +416,22 @@ struct FunctionInfo {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Converts a Carbon parameter type to the parameter type that should be used
|
||||
// for the C++ declaration of the Carbon -> Carbon thunk. This is always a
|
||||
// reference type.
|
||||
static auto MapToCppThunkParamType(Context& context, SemIR::TypeId type_id)
|
||||
-> clang::QualType {
|
||||
auto cpp_type = MapToCppType(context, type_id);
|
||||
if (cpp_type.isNull()) {
|
||||
return clang::QualType();
|
||||
}
|
||||
// The function exposed to C++ may have a `const&` parameter type for a value
|
||||
// parameter. Always use a const reference here so we accept the argument,
|
||||
// even though we might not need the `const`.
|
||||
return context.ast_context().getLValueReferenceType(
|
||||
context.ast_context().getConstType(cpp_type));
|
||||
}
|
||||
|
||||
// Create a `clang::FunctionDecl` for the given Carbon function. This
|
||||
// can be used to call the Carbon function from C++. The Carbon
|
||||
// function's ABI must be compatible with C++.
|
||||
@@ -434,22 +450,20 @@ static auto BuildCppFunctionDeclForCarbonFn(Context& context,
|
||||
// Get parameters types.
|
||||
llvm::SmallVector<clang::QualType> cpp_param_types;
|
||||
if (callee.self_param) {
|
||||
auto cpp_type = MapToCppType(context, callee.self_param->type_id);
|
||||
auto cpp_type = MapToCppThunkParamType(context, callee.self_param->type_id);
|
||||
if (cpp_type.isNull()) {
|
||||
context.TODO(loc_id, "failed to map Carbon self type to C++");
|
||||
return nullptr;
|
||||
}
|
||||
cpp_type = context.ast_context().getLValueReferenceType(cpp_type);
|
||||
cpp_param_types.push_back(cpp_type);
|
||||
}
|
||||
for (auto param : callee.explicit_params) {
|
||||
auto cpp_type = MapToCppType(context, param.type_id);
|
||||
auto cpp_type = MapToCppThunkParamType(context, param.type_id);
|
||||
if (cpp_type.isNull()) {
|
||||
context.TODO(loc_id, "failed to map Carbon type to C++");
|
||||
return nullptr;
|
||||
}
|
||||
auto ref_type = context.ast_context().getLValueReferenceType(cpp_type);
|
||||
cpp_param_types.push_back(ref_type);
|
||||
cpp_param_types.push_back(cpp_type);
|
||||
}
|
||||
|
||||
CARBON_CHECK(function.return_type_inst_id == SemIR::TypeInstId::None);
|
||||
@@ -508,12 +522,17 @@ static auto BuildCppToCarbonThunkDecl(
|
||||
context.TODO(loc_id, "failed to map Carbon return type to C++ type");
|
||||
return nullptr;
|
||||
}
|
||||
if (cpp_return_type->isArrayType()) {
|
||||
// C++ doesn't support returning arrays by value.
|
||||
context.TODO(loc_id, "array return type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
clang::DeclarationNameInfo name_info(thunk_name, clang_loc);
|
||||
|
||||
auto ext_proto_info = clang::FunctionProtoType::ExtProtoInfo();
|
||||
if (target.self_param && target.self_param->is_ref) {
|
||||
if (target.self_param && target.self_param->kind == ParamPatternKind::Ref) {
|
||||
ext_proto_info.RefQualifier = clang::RQ_LValue;
|
||||
}
|
||||
clang::QualType thunk_function_type = ast_context.getFunctionType(
|
||||
@@ -657,6 +676,39 @@ static auto BuildCppToCarbonThunkBody(clang::Sema& sema,
|
||||
clang_loc);
|
||||
}
|
||||
|
||||
// Returns whether the given Carbon parameter should be passed as a C++ const
|
||||
// reference.
|
||||
static auto PassAsConstRef(Context& /*context*/,
|
||||
const FunctionInfo::Param& param,
|
||||
clang::QualType cpp_type) -> bool {
|
||||
// Use pass-by-const-ref for value parameters of array type.
|
||||
// TODO: Should we do this for value parameters of any type that uses a
|
||||
// pointer value representation?
|
||||
return param.kind == ParamPatternKind::Value && cpp_type->isArrayType();
|
||||
}
|
||||
|
||||
// Converts a Carbon parameter type to the parameter type that should be exposed
|
||||
// to C++ callers.
|
||||
static auto MapToCppParamType(Context& context, SemIR::LocId loc_id,
|
||||
const FunctionInfo::Param& param)
|
||||
-> clang::QualType {
|
||||
auto cpp_type = MapToCppType(context, param.type_id);
|
||||
if (cpp_type.isNull()) {
|
||||
return clang::QualType();
|
||||
}
|
||||
if (param.kind == Check::ParamPatternKind::Ref) {
|
||||
cpp_type = context.ast_context().getLValueReferenceType(cpp_type);
|
||||
} else if (PassAsConstRef(context, param, cpp_type)) {
|
||||
cpp_type = context.ast_context().getLValueReferenceType(
|
||||
context.ast_context().getConstType(cpp_type));
|
||||
} else if (cpp_type->isArrayType()) {
|
||||
// C++ doesn't support passing arrays by value.
|
||||
context.TODO(loc_id, "by-var array parameter");
|
||||
return clang::QualType();
|
||||
}
|
||||
return cpp_type;
|
||||
}
|
||||
|
||||
// Create a C++ thunk that calls the Carbon thunk. The C++ thunk's
|
||||
// parameter types are mapped from the parameters of the target function
|
||||
// with `MapToCppType`. (Note that the target function here is the
|
||||
@@ -670,19 +722,19 @@ static auto BuildCppToCarbonThunk(Context& context, SemIR::LocId loc_id,
|
||||
|
||||
llvm::SmallVector<clang::QualType> param_types;
|
||||
for (auto param : target.explicit_params) {
|
||||
auto cpp_type = MapToCppType(context, param.type_id);
|
||||
auto cpp_type = MapToCppParamType(context, loc_id, param);
|
||||
if (cpp_type.isNull()) {
|
||||
context.TODO(loc_id, "failed to map C++ type to Carbon");
|
||||
return nullptr;
|
||||
}
|
||||
if (param.is_ref) {
|
||||
cpp_type = context.ast_context().getLValueReferenceType(cpp_type);
|
||||
}
|
||||
param_types.push_back(cpp_type);
|
||||
}
|
||||
|
||||
auto* thunk_function_decl = BuildCppToCarbonThunkDecl(
|
||||
context, loc_id, target, &thunk_ident, param_types);
|
||||
if (!thunk_function_decl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Build the thunk function body.
|
||||
clang::Sema& sema = context.clang_sema();
|
||||
@@ -863,6 +915,9 @@ auto ExportDestructorToCpp(Context& context, const SemIR::Class& class_info,
|
||||
auto thunk_function_id = BuildDestroyThunk(context, loc_id, class_info);
|
||||
auto* cpp_function_decl =
|
||||
BuildCppFunctionDeclForCarbonFn(context, loc_id, thunk_function_id);
|
||||
if (!cpp_function_decl) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Build the destructor body.
|
||||
clang::Sema::ContextRAII context_raii(sema, cpp_destructor_decl);
|
||||
|
||||
Reference in New Issue
Block a user