Repository: carbon-language/carbon-lang
File: toolchain/check/import_cpp.cpp (C++)

Code before:
    context.TODO(loc_id, "Unsupported: Variadic function");
    return SemIR::ErrorInst::SingletonInstId;
  }
  if (!clang_decl->isGlobal()) {
    context.TODO(loc_id, "Unsupported: Non-global function");
    return SemIR::ErrorInst::SingletonInstId;
  }
  if (clang_decl->getTemplatedKind() != clang::FunctionDecl::TK_NonTemplate) {
    context.TODO(loc_id, "Unsupported: Template function");
    return SemIR::ErrorInst::SingletonInstId;
  }
  if (!clang_decl->param_empty()) {
    context.TODO(loc_id, "Unsupported: Function with parameters");
    return SemIR::ErrorInst::SingletonInstId;
  }

  if (!clang_decl->getReturnType()->isVoidType() &&
      clang_decl->getReturnType().getAsString() != "int") {
    context.TODO(loc_id, "Unsupported: Function return type");
    return SemIR::ErrorInst::SingletonInstId;
  }

  auto function_decl = SemIR::FunctionDecl{
      SemIR::TypeId::None, SemIR::FunctionId::None, SemIR::InstBlockId::Empty};
  auto decl_id = AddPlaceholderInst(
      context, SemIR::LocIdAndInst(Parse::NodeId::None, function_decl));

  auto return_slot_pattern_id = SemIR::InstId::None;
  if (clang_decl->getReturnType().getAsString() == "int") {
    auto size_id = context.ints().Add(32);
    auto type_id = MakeIntType(context, Parse::NodeId::None,
                               SemIR::IntKind::Signed, size_id);
    auto type_inst_id = MakeIntTypeLiteral(context, Parse::NodeId::None,
                                           SemIR::IntKind::Signed, size_id);

    return_slot_pattern_id = AddInstInNoBlock(
        context, SemIR::LocIdAndInst::NoLoc(SemIR::ReturnSlotPattern(
                     {.type_id = type_id, .type_inst_id = type_inst_id})));
    auto param_pattern_id = AddInstInNoBlock(
        context, SemIR::LocIdAndInst::NoLoc(SemIR::OutParamPattern(
                     {.type_id = type_id,
                      .subpattern_id = return_slot_pattern_id,
                      .index = SemIR::CallParamIndex::None})));
    return_slot_pattern_id = param_pattern_id;
  }

  auto function_info = SemIR::Function{
      {.name_id = name_id,
       .parent_scope_id = scope_id,
       .generic_id = SemIR::GenericId::None,
       .first_param_node_id = Parse::NodeId::None,

Review comment (refactor):
Can we move this to after we create the return type?
If so, we could merge the condition that check the return type is supported and the condition switches over the return type.

Code after:
// TODO: Support more return types.
static auto GetReturnType(Context& context, SemIRLoc loc_id,
                          const clang::FunctionDecl* clang_decl)
    -> SemIR::InstId {
  clang::QualType ret_type = clang_decl->getReturnType().getCanonicalType();
  if (ret_type->isVoidType()) {
    return SemIR::InstId::None;
  }
  if (const auto* builtin_type = dyn_cast<clang::BuiltinType>(ret_type);
      builtin_type && builtin_type->getKind() == clang::BuiltinType::Int) {
    constexpr int SupportedIntWidth = 32;
    uint64_t int_size = context.ast_context().getTypeSize(ret_type);
    if (int_size != SupportedIntWidth) {
      // TODO: Add tests for this case.
      context.TODO(loc_id,
                   llvm::formatv("Unsupported: return type: {0}, size: {1}",
                                 ret_type.getAsString(), int_size));
      return SemIR::ErrorInst::SingletonInstId;
    }
    IntId size_id = context.ints().Add(int_size);
    // TODO: Fill in a location for the type once available.
    SemIR::TypeId type_id = MakeIntType(context, Parse::NodeId::None,
                                        SemIR::IntKind::Signed, size_id);
    // TODO: Fill in a location for the type once available.
    SemIR::InstId type_inst_id = MakeIntTypeLiteral(
        context, Parse::NodeId::None, SemIR::IntKind::Signed, size_id);

    SemIR::InstId return_slot_pattern_id = AddInstInNoBlock(
        // TODO: Fill in a location for the return type once available.
        context, SemIR::LocIdAndInst::NoLoc(SemIR::ReturnSlotPattern(
                     {.type_id = type_id, .type_inst_id = type_inst_id})));
    SemIR::InstId param_pattern_id = AddInstInNoBlock(
        // TODO: Fill in a location for the return type once available.
        context, SemIR::LocIdAndInst::NoLoc(SemIR::OutParamPattern(
                     {.type_id = type_id,
                      .subpattern_id = return_slot_pattern_id,
                      .index = SemIR::CallParamIndex::None})));
    return param_pattern_id;
  }
  context.TODO(loc_id, llvm::formatv("Unsupported: return type: {0}",
                                     ret_type.getAsString()));
  return SemIR::ErrorInst::SingletonInstId;
}

// 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,
                               SemIR::NameScopeId scope_id,
                               SemIR::NameId name_id,
                               const clang::FunctionDecl* clang_decl)
    -> SemIR::InstId {