mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-02 12:35:56 +01:00
Fix C++ function params and return values printed in SemIR (#5468)
Fix `pattern_block_id` and `call_params_id` for C++ function decl
import, to get the correct SemIR printout for the C++ functions i.e.
1) Fill in missing parameter info in the function decls:
```
// CHECK:STDOUT: %foo.decl: %foo.type = fn_decl @foo [concrete = constants.%foo] {
// CHECK:STDOUT: %a.patt: %pattern_type.2f8 = binding_pattern a [concrete]
// CHECK:STDOUT: %a.param_patt: %pattern_type.2f8 = value_param_pattern %a.patt, call_param0 [concrete]
// CHECK:STDOUT: } {
// CHECK:STDOUT: %a.param: %i16 = value_param call_param0
// CHECK:STDOUT: %.1: type = splice_block %i16 [concrete = constants.%i16] {
// CHECK:STDOUT: %int_16: Core.IntLiteral = int_value 16 [concrete = constants.%int_16]
// CHECK:STDOUT: %i16: type = class_type @Int, @Int(constants.%int_16) [concrete = constants.%i16]
// CHECK:STDOUT: }
// CHECK:STDOUT: %a: %i16 = bind_name a, %a.param
// CHECK:STDOUT: }
```
2) Print the params and return values:
```
// CHECK:STDOUT: fn @foo_short() -> %i16;
```
```
// CHECK:STDOUT: fn @foo(%a.param: %i16);
```
Closes #5449
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
#include "toolchain/check/import.h"
|
||||
#include "toolchain/check/inst.h"
|
||||
#include "toolchain/check/literal.h"
|
||||
#include "toolchain/check/pattern.h"
|
||||
#include "toolchain/check/pattern_match.h"
|
||||
#include "toolchain/check/type.h"
|
||||
#include "toolchain/diagnostics/diagnostic.h"
|
||||
#include "toolchain/diagnostics/format_providers.h"
|
||||
@@ -341,53 +343,67 @@ static auto MapType(Context& context, clang::QualType type) -> TypeExpr {
|
||||
// declaration. If the function declaration has no parameters, it returns
|
||||
// `SemIR::InstBlockId::Empty`. In the case of an unsupported parameter type, it
|
||||
// returns `SemIR::InstBlockId::None`.
|
||||
// TODO: Consider refactoring to extract and reuse more logic from
|
||||
// `HandleAnyBindingPattern()`.
|
||||
static auto MakeParamPatternsBlockId(Context& context, SemIR::LocId loc_id,
|
||||
const clang::FunctionDecl& clang_decl)
|
||||
-> SemIR::InstBlockId {
|
||||
if (clang_decl.parameters().empty()) {
|
||||
return SemIR::InstBlockId::Empty;
|
||||
}
|
||||
SemIR::CallParamIndex next_index(0);
|
||||
llvm::SmallVector<SemIR::InstId> params;
|
||||
params.reserve(clang_decl.parameters().size());
|
||||
for (const clang::ParmVarDecl* param : clang_decl.parameters()) {
|
||||
clang::QualType param_type = param->getType().getCanonicalType();
|
||||
SemIR::TypeId type_id =
|
||||
GetPatternType(context, MapType(context, param_type).type_id);
|
||||
|
||||
// Mark the start of a region of insts, needed for the type expression
|
||||
// created later with the call of `EndSubpatternAsExpr()`.
|
||||
BeginSubpattern(context);
|
||||
auto [type_inst_id, type_id] = MapType(context, param_type);
|
||||
// Type expression of the binding pattern - a single-entry/single-exit
|
||||
// region that allows control flow in the type expression e.g. fn F(x: if C
|
||||
// then i32 else i64).
|
||||
SemIR::ExprRegionId type_expr_region_id =
|
||||
EndSubpatternAsExpr(context, type_inst_id);
|
||||
|
||||
if (type_id == SemIR::ErrorInst::TypeId) {
|
||||
context.TODO(loc_id, llvm::formatv("Unsupported: parameter type: {0}",
|
||||
param_type.getAsString()));
|
||||
return SemIR::InstBlockId::None;
|
||||
}
|
||||
|
||||
llvm::StringRef param_name = param->getName();
|
||||
SemIR::EntityNameId entity_name_id = context.entity_names().Add(
|
||||
{.name_id =
|
||||
(param_name.empty())
|
||||
// Translate an unnamed parameter to an underscore to
|
||||
// match Carbon's naming of unnamed/unused function params.
|
||||
? SemIR::NameId::Underscore
|
||||
: SemIR::NameId::ForIdentifier(
|
||||
context.sem_ir().identifiers().Add(param_name)),
|
||||
.parent_scope_id = SemIR::NameScopeId::None});
|
||||
SemIR::InstId binding_pattern_id = AddInstInNoBlock(
|
||||
SemIR::NameId name_id =
|
||||
param_name.empty()
|
||||
// Translate an unnamed parameter to an underscore to
|
||||
// match Carbon's naming of unnamed/unused function params.
|
||||
? SemIR::NameId::Underscore
|
||||
: SemIR::NameId::ForIdentifier(
|
||||
context.sem_ir().identifiers().Add(param_name));
|
||||
|
||||
// TODO: Fix this once templates are supported.
|
||||
bool is_template = false;
|
||||
// TODO: Fix this once generics are supported.
|
||||
bool is_generic = false;
|
||||
SemIR::InstId binding_pattern_id =
|
||||
// TODO: Fill in a location once available.
|
||||
context, SemIR::LocIdAndInst::NoLoc(SemIR::BindingPattern(
|
||||
{.type_id = type_id, .entity_name_id = entity_name_id})));
|
||||
SemIR::InstId var_pattern_id = AddInstInNoBlock(
|
||||
AddBindingPattern(context, SemIR::LocId::None, name_id, type_id,
|
||||
type_expr_region_id, is_generic, is_template)
|
||||
.pattern_id;
|
||||
SemIR::InstId var_pattern_id = AddPatternInst(
|
||||
context,
|
||||
// TODO: Fill in a location once available.
|
||||
SemIR::LocIdAndInst::NoLoc(SemIR::ValueParamPattern(
|
||||
{.type_id = context.insts().Get(binding_pattern_id).type_id(),
|
||||
.subpattern_id = binding_pattern_id,
|
||||
.index = next_index})));
|
||||
++next_index.index;
|
||||
.index = SemIR::CallParamIndex::None})));
|
||||
params.push_back(var_pattern_id);
|
||||
}
|
||||
return context.inst_blocks().Add(params);
|
||||
}
|
||||
|
||||
// Returns the return type of the given function declaration.
|
||||
// Currently only void and 32-bit int are supported.
|
||||
// Returns the return type of the given function declaration. In case of an
|
||||
// unsupported return type, it returns `SemIR::ErrorInst::InstId`.
|
||||
// TODO: Support more return types.
|
||||
static auto GetReturnType(Context& context, SemIR::LocId loc_id,
|
||||
const clang::FunctionDecl* clang_decl)
|
||||
@@ -396,6 +412,7 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id,
|
||||
if (ret_type->isVoidType()) {
|
||||
return SemIR::InstId::None;
|
||||
}
|
||||
|
||||
auto [type_inst_id, type_id] = MapType(context, ret_type);
|
||||
if (type_id == SemIR::ErrorInst::TypeId) {
|
||||
context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
|
||||
@@ -403,12 +420,12 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id,
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
auto pattern_type_id = GetPatternType(context, type_id);
|
||||
SemIR::InstId return_slot_pattern_id = AddInstInNoBlock(
|
||||
SemIR::InstId return_slot_pattern_id = AddPatternInst(
|
||||
// TODO: Fill in a location for the return type once available.
|
||||
context,
|
||||
SemIR::LocIdAndInst::NoLoc(SemIR::ReturnSlotPattern(
|
||||
{.type_id = pattern_type_id, .type_inst_id = type_inst_id})));
|
||||
SemIR::InstId param_pattern_id = AddInstInNoBlock(
|
||||
SemIR::InstId param_pattern_id = AddPatternInst(
|
||||
// TODO: Fill in a location for the return type once available.
|
||||
context, SemIR::LocIdAndInst::NoLoc(SemIR::OutParamPattern(
|
||||
{.type_id = pattern_type_id,
|
||||
@@ -417,6 +434,46 @@ static auto GetReturnType(Context& context, SemIR::LocId loc_id,
|
||||
return param_pattern_id;
|
||||
}
|
||||
|
||||
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 param_patterns_id;
|
||||
SemIR::InstId return_slot_pattern_id;
|
||||
SemIR::InstBlockId call_params_id;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// Creates a block containing the parameter pattern instructions for the
|
||||
// explicit parameters, a parameter pattern instruction for the return type and
|
||||
// a block containing the call parameters of the function. Emits a callee
|
||||
// pattern-match for the explicit parameter patterns and the return slot pattern
|
||||
// to create the Call parameters instructions block. Currently the implicit
|
||||
// parameter patterns are not taken into account. Returns the parameter patterns
|
||||
// block id, the return slot pattern id, and the call parameters block id.
|
||||
// Returns `std::nullopt` if the function declaration has an unsupported
|
||||
// parameter type.
|
||||
static auto CreateFunctionParamsInsts(Context& context, SemIR::LocId loc_id,
|
||||
const clang::FunctionDecl* clang_decl)
|
||||
-> std::optional<FunctionParamsInsts> {
|
||||
auto param_patterns_id =
|
||||
MakeParamPatternsBlockId(context, loc_id, *clang_decl);
|
||||
if (!param_patterns_id.has_value()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto return_slot_pattern_id = GetReturnType(context, loc_id, clang_decl);
|
||||
if (SemIR::ErrorInst::InstId == return_slot_pattern_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);
|
||||
return {{.param_patterns_id = param_patterns_id,
|
||||
.return_slot_pattern_id = return_slot_pattern_id,
|
||||
.call_params_id = call_params_id}};
|
||||
}
|
||||
|
||||
// Imports a function declaration from Clang to Carbon. If successful, returns
|
||||
// the new Carbon function declaration `InstId`.
|
||||
static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
@@ -436,18 +493,22 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
context.TODO(loc_id, "Unsupported: Template function");
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
auto param_patterns_id =
|
||||
MakeParamPatternsBlockId(context, loc_id, *clang_decl);
|
||||
if (!param_patterns_id.has_value()) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
auto return_slot_pattern_id = GetReturnType(context, loc_id, clang_decl);
|
||||
if (SemIR::ErrorInst::InstId == return_slot_pattern_id) {
|
||||
|
||||
context.inst_block_stack().Push();
|
||||
context.pattern_block_stack().Push();
|
||||
|
||||
auto function_params_insts =
|
||||
CreateFunctionParamsInsts(context, loc_id, clang_decl);
|
||||
|
||||
auto pattern_block_id = context.pattern_block_stack().Pop();
|
||||
auto decl_block_id = context.inst_block_stack().Pop();
|
||||
|
||||
if (!function_params_insts.has_value()) {
|
||||
return SemIR::ErrorInst::InstId;
|
||||
}
|
||||
|
||||
auto function_decl = SemIR::FunctionDecl{
|
||||
SemIR::TypeId::None, SemIR::FunctionId::None, SemIR::InstBlockId::Empty};
|
||||
SemIR::TypeId::None, SemIR::FunctionId::None, decl_block_id};
|
||||
auto decl_id =
|
||||
AddPlaceholderInstInNoBlock(context, Parse::NodeId::None, function_decl);
|
||||
context.imports().push_back(decl_id);
|
||||
@@ -458,16 +519,16 @@ static auto ImportFunctionDecl(Context& context, SemIR::LocId loc_id,
|
||||
.generic_id = SemIR::GenericId::None,
|
||||
.first_param_node_id = Parse::NodeId::None,
|
||||
.last_param_node_id = Parse::NodeId::None,
|
||||
.pattern_block_id = SemIR::InstBlockId::Empty,
|
||||
.pattern_block_id = pattern_block_id,
|
||||
.implicit_param_patterns_id = SemIR::InstBlockId::Empty,
|
||||
.param_patterns_id = param_patterns_id,
|
||||
.param_patterns_id = function_params_insts->param_patterns_id,
|
||||
.is_extern = false,
|
||||
.extern_library_id = SemIR::LibraryNameId::None,
|
||||
.non_owning_decl_id = SemIR::InstId::None,
|
||||
.first_owning_decl_id = decl_id,
|
||||
.definition_id = SemIR::InstId::None},
|
||||
{.call_params_id = SemIR::InstBlockId::Empty,
|
||||
.return_slot_pattern_id = return_slot_pattern_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,
|
||||
.clang_decl_id = context.sem_ir().clang_decls().Add(clang_decl)}};
|
||||
|
||||
Reference in New Issue
Block a user