mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
Prevent ref self methods from being called from C++ with an rvalue (#7130)
If the Carbon method takes a `ref self`, give the C++ thunk an lvalue ref-qualifier.
This commit is contained in:
@@ -4,6 +4,8 @@
|
||||
|
||||
#include "toolchain/check/cpp/export.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "toolchain/check/cpp/import.h"
|
||||
#include "toolchain/check/cpp/location.h"
|
||||
@@ -330,6 +332,11 @@ auto CalculateCppFieldOffsets(
|
||||
namespace {
|
||||
struct FunctionInfo {
|
||||
struct Param {
|
||||
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)) {}
|
||||
|
||||
// Type of the parameter's scrutinee.
|
||||
SemIR::TypeId type_id;
|
||||
|
||||
@@ -346,15 +353,13 @@ struct FunctionInfo {
|
||||
auto function_params =
|
||||
context.inst_blocks().Get(function.call_param_patterns_id);
|
||||
|
||||
// Get the function's `self` parameter type, if present.
|
||||
// Get the function's `self` parameter, if present.
|
||||
if (function.call_param_ranges.implicit_size() > 0) {
|
||||
CARBON_CHECK(function.call_param_ranges.implicit_size() == 1);
|
||||
|
||||
auto param_inst_id =
|
||||
function_params[function.call_param_ranges.implicit_begin().index];
|
||||
auto scrutinee_type_id = ExtractScrutineeType(
|
||||
context.sem_ir(), context.insts().Get(param_inst_id).type_id());
|
||||
self_type_id = scrutinee_type_id;
|
||||
self_param = Param(context, param_inst_id);
|
||||
}
|
||||
|
||||
// Get the function's explicit parameters.
|
||||
@@ -363,25 +368,27 @@ struct FunctionInfo {
|
||||
function_params =
|
||||
function_params.drop_back(function.call_param_ranges.return_size());
|
||||
for (auto param_inst_id : function_params) {
|
||||
explicit_params.push_back(
|
||||
{.type_id = ExtractScrutineeType(
|
||||
context.sem_ir(), context.insts().Get(param_inst_id).type_id()),
|
||||
.is_ref =
|
||||
context.insts().Is<SemIR::RefParamPattern>(param_inst_id)});
|
||||
explicit_params.push_back(Param(context, param_inst_id));
|
||||
}
|
||||
}
|
||||
|
||||
// Get the `StorageClass` to use for `CXXMethodDecl`s.
|
||||
auto GetStorageClass() const -> clang::StorageClass {
|
||||
if (has_self()) {
|
||||
if (self_param) {
|
||||
return clang::SC_None;
|
||||
} else {
|
||||
return clang::SC_Static;
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the function has a `self` parameter.
|
||||
auto has_self() const -> bool { return self_type_id != SemIR::TypeId::None; }
|
||||
// Get the `self` param type, or `None` if the function does not have
|
||||
// a `self` param.
|
||||
auto GetSelfTypeId() const -> SemIR::TypeId {
|
||||
if (self_param) {
|
||||
return self_param->type_id;
|
||||
}
|
||||
return SemIR::TypeId::None;
|
||||
}
|
||||
|
||||
SemIR::FunctionId function_id;
|
||||
const SemIR::Function& function;
|
||||
@@ -395,9 +402,9 @@ struct FunctionInfo {
|
||||
// and whether the parameter is a reference.
|
||||
llvm::SmallVector<Param> explicit_params;
|
||||
|
||||
// Type of the function's `self` parameter, or `None` if the function
|
||||
// is not a method.
|
||||
SemIR::TypeId self_type_id = SemIR::TypeId::None;
|
||||
// For methods, the type of `self` and whether it is a reference. If
|
||||
// the function does not have a `self` parameter, this is `nullopt`.
|
||||
std::optional<Param> self_param;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -418,8 +425,8 @@ static auto BuildCppFunctionDeclForCarbonFn(Context& context,
|
||||
|
||||
// Get parameters types.
|
||||
llvm::SmallVector<clang::QualType> cpp_param_types;
|
||||
if (callee.has_self()) {
|
||||
auto cpp_type = MapToCppType(context, callee.self_type_id);
|
||||
if (callee.self_param) {
|
||||
auto cpp_type = MapToCppType(context, callee.self_param->type_id);
|
||||
if (cpp_type.isNull()) {
|
||||
context.TODO(loc_id, "failed to map Carbon self type to C++");
|
||||
return nullptr;
|
||||
@@ -497,6 +504,9 @@ static auto BuildCppToCarbonThunkDecl(
|
||||
clang::DeclarationNameInfo name_info(thunk_name, clang_loc);
|
||||
|
||||
auto ext_proto_info = clang::FunctionProtoType::ExtProtoInfo();
|
||||
if (target.self_param && target.self_param->is_ref) {
|
||||
ext_proto_info.RefQualifier = clang::RQ_LValue;
|
||||
}
|
||||
clang::QualType thunk_function_type = ast_context.getFunctionType(
|
||||
cpp_return_type, thunk_param_types, ext_proto_info);
|
||||
|
||||
@@ -587,7 +597,7 @@ static auto BuildCppToCarbonThunkBody(clang::Sema& sema,
|
||||
|
||||
llvm::SmallVector<clang::Expr*> call_args;
|
||||
// For methods, pass the `this` pointer as the first argument to the callee.
|
||||
if (target.has_self()) {
|
||||
if (target.self_param) {
|
||||
auto* parent_class = cast<clang::CXXRecordDecl>(target.decl_context);
|
||||
clang::QualType class_type =
|
||||
sema.getASTContext().getCanonicalTagType(parent_class);
|
||||
@@ -702,7 +712,7 @@ static auto BuildCarbonToCarbonThunk(Context& context, SemIR::LocId loc_id,
|
||||
context, loc_id,
|
||||
{.parent_scope_id = target.function.parent_scope_id,
|
||||
.name_id = thunk_name_id,
|
||||
.self_type_id = target.self_type_id,
|
||||
.self_type_id = target.GetSelfTypeId(),
|
||||
.param_type_ids = thunk_param_type_ids,
|
||||
.param_kind = ParamPatternKind::Ref})
|
||||
.second;
|
||||
|
||||
Reference in New Issue
Block a user