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

Code before:
}

// Returns whether the function is an imported C++ operator member function.
static auto IsCppOperatorMethod(Context& context, SemIR::FunctionId function_id)
    -> bool {
  SemIR::ClangDeclId clang_decl_id =
      context.functions().Get(function_id).clang_decl_id;
  if (!clang_decl_id.has_value()) {
    return false;
  }

  auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(
      context.clang_decls().Get(clang_decl_id).decl);
  return clang_method_decl && clang_method_decl->isOverloadedOperator();
}

auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
                                  SemIR::CppOverloadSetId overload_set_id,
                                  SemIR::InstId self_id,
                                  llvm::ArrayRef<SemIR::InstId> arg_ids)
    -> std::tuple<SemIR::InstId, SemIR::CalleeFunction,
                  llvm::ArrayRef<SemIR::InstId>> {
  SemIR::InstId callee_id =
      ResolveCalleeId(context, loc_id, overload_set_id, self_id, arg_ids);
  SemIR::CalleeFunction callee_function =
      GetCalleeFunction(context.sem_ir(), callee_id);
  if (callee_function.is_error) {
    return {SemIR::ErrorInst::InstId, callee_function, arg_ids};
  }

  CARBON_CHECK(!callee_function.cpp_overload_set_id.has_value());

  CARBON_CHECK(!callee_function.self_id.has_value());
  if (self_id.has_value()) {
    // Preserve the `self` argument from the original callee.
    callee_function.self_id = self_id;
  } else if (IsCppOperatorMethod(context, callee_function.function_id)) {
    // Adjust `self` and args for C++ overloaded operator methods.
    callee_function.self_id = arg_ids.consume_front();
  }
  return {callee_id, callee_function, arg_ids};
}

}  // namespace Carbon::Check


Review comment (suggestion):
Minor, but you might consider making this a struct... Others have pushed me for that over a `tuple` return.

Also, a struct could be used to switch this to use RVO (with a slightly different assignment flow). I'm mainly thinking of that because of the `CalleeFunction` cost.

Code after:
      candidate_set.NoteCandidates(
          clang::PartialDiagnosticAt(
              loc, sema.PDiag(clang::diag::err_ovl_ambiguous_call)
                       << GetCppName(context, overload_set.name_id)),
          sema, clang::OCD_AmbiguousCandidates, arg_exprs);
      return SemIR::ErrorInst::InstId;
    }
    case clang::OverloadingResult::OR_Deleted: {
      sema.DiagnoseUseOfDeletedFunction(
          loc, clang::SourceRange(loc, loc),
          GetCppName(context, overload_set.name_id), candidate_set,
          best_viable_fn->Function, arg_exprs);
      return SemIR::ErrorInst::InstId;
    }
  }
}

// Returns whether the function is an imported C++ operator member function.
static auto IsCppOperatorMethod(Context& context, SemIR::FunctionId function_id)
    -> bool {
  SemIR::ClangDeclId clang_decl_id =
      context.functions().Get(function_id).clang_decl_id;
  return clang_decl_id.has_value() &&
         IsOperatorMethodDecl(
             context.clang_decls().Get(clang_decl_id).key.decl);
}

auto PerformCppOverloadResolution(Context& context, SemIR::LocId loc_id,
                                  SemIR::CppOverloadSetId overload_set_id,
                                  SemIR::InstId self_id,
                                  llvm::ArrayRef<SemIR::InstId> arg_ids)
    -> CppOverloadResolutionResult {
  CppOverloadResolutionResult result = {
      .callee_id =
          ResolveCalleeId(context, loc_id, overload_set_id, self_id, arg_ids),
      .arg_ids = arg_ids};
  SemIR::Callee callee = GetCallee(context.sem_ir(), result.callee_id);
  CARBON_KIND_SWITCH(callee) {
    case CARBON_KIND(SemIR::CalleeError _): {
      result.callee_id = SemIR::ErrorInst::InstId;
      return result;
    }
    case CARBON_KIND(SemIR::CalleeFunction fn): {
      CARBON_CHECK(!fn.self_id.has_value());
      if (self_id.has_value()) {
        // Preserve the `self` argument from the original callee.
        fn.self_id = self_id;
      } else if (IsCppOperatorMethod(context, fn.function_id)) {
        // Adjust `self` and args for C++ overloaded operator methods.
        fn.self_id = result.arg_ids.consume_front();
      }