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

Code before:
    return SemIR::InstId::None;
  }

  // Make sure all operands are complete before lookup.
  for (SemIR::InstId arg_id : arg_ids) {
    SemIR::TypeId arg_type_id = context.insts().Get(arg_id).type_id();
    if (!RequireCompleteType(context, arg_type_id, loc_id, [&] {
          CARBON_DIAGNOSTIC(
              IncompleteOperandTypeInCppOperatorLookup, Error,
              "looking up a C++ operator with incomplete operand type {0}",
              SemIR::TypeId);
          return context.emitter().Build(
              loc_id, IncompleteOperandTypeInCppOperatorLookup, arg_type_id);
        })) {
      return SemIR::ErrorInst::InstId;
    }
  }

  auto arg_exprs = InventClangArgs(context, arg_ids);
  if (!arg_exprs.has_value()) {
    return SemIR::ErrorInst::InstId;
  }

  clang::SourceLocation loc = GetCppLocation(context, loc_id);
  clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
      *op_kind, loc, true);
  clang::UnresolvedSet<4> functions;
  clang::OverloadCandidateSet candidate_set(
      loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
  // This works for both unary and binary operators.
  context.clang_sema().LookupOverloadedBinOp(candidate_set, *op_kind, functions,
                                             *arg_exprs);

  for (auto& it : candidate_set) {
    if (!it.Function) {
      continue;
    }
    functions.addDecl(it.Function, it.FoundDecl.getAccess());
  }

  return ImportCppOverloadSet(
      context, SemIR::NameScopeId::None, SemIR::NameId::CppOperator,
      /*naming_class=*/nullptr, std::move(functions), operator_rewrite_info);
}

auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
  auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
  return clang_method_decl && clang_method_decl->isOverloadedOperator();
}

}  // namespace Carbon::Check

Review comment (suggestion):
Optional: Something like this might be clearer to someone unfamiliar with Clang:

```suggestion
      *op_kind, loc, /*AllowRewritten=*/true);
```

Code after:
    return SemIR::InstId::None;
  }

  // Make sure all operands are complete before lookup.
  for (SemIR::InstId arg_id : arg_ids) {
    SemIR::TypeId arg_type_id = context.insts().Get(arg_id).type_id();
    if (!RequireCompleteType(context, arg_type_id, loc_id, [&] {
          CARBON_DIAGNOSTIC(
              IncompleteOperandTypeInCppOperatorLookup, Error,
              "looking up a C++ operator with incomplete operand type {0}",
              SemIR::TypeId);
          return context.emitter().Build(
              loc_id, IncompleteOperandTypeInCppOperatorLookup, arg_type_id);
        })) {
      return SemIR::ErrorInst::InstId;
    }
  }

  auto arg_exprs = InventClangArgs(context, arg_ids);
  if (!arg_exprs.has_value()) {
    return SemIR::ErrorInst::InstId;
  }

  clang::SourceLocation loc = GetCppLocation(context, loc_id);
  clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
      *op_kind, loc, /*AllowRewritten=*/true);
  clang::UnresolvedSet<4> functions;
  clang::OverloadCandidateSet candidate_set(
      loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
  // This works for both unary and binary operators.
  context.clang_sema().LookupOverloadedBinOp(candidate_set, *op_kind, functions,
                                             *arg_exprs);

  for (auto& it : candidate_set) {
    if (!it.Function) {
      continue;
    }
    functions.addDecl(it.Function, it.FoundDecl.getAccess());
  }

  return ImportCppOverloadSet(
      context, SemIR::NameScopeId::None, SemIR::NameId::CppOperator,
      /*naming_class=*/nullptr, std::move(functions), operator_rewrite_info);
}

auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
  auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
  return clang_method_decl && clang_method_decl->isOverloadedOperator();
}

}  // namespace Carbon::Check