operators.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/check/cpp/operators.h"
  5. #include "clang/Sema/Initialization.h"
  6. #include "clang/Sema/Overload.h"
  7. #include "clang/Sema/Sema.h"
  8. #include "toolchain/check/convert.h"
  9. #include "toolchain/check/core_identifier.h"
  10. #include "toolchain/check/cpp/import.h"
  11. #include "toolchain/check/cpp/location.h"
  12. #include "toolchain/check/cpp/overload_resolution.h"
  13. #include "toolchain/check/cpp/type_mapping.h"
  14. #include "toolchain/check/function.h"
  15. #include "toolchain/check/inst.h"
  16. #include "toolchain/check/type.h"
  17. #include "toolchain/check/type_completion.h"
  18. #include "toolchain/sem_ir/builtin_function_kind.h"
  19. #include "toolchain/sem_ir/cpp_initializer_list.h"
  20. #include "toolchain/sem_ir/ids.h"
  21. #include "toolchain/sem_ir/inst.h"
  22. #include "toolchain/sem_ir/typed_insts.h"
  23. namespace Carbon::Check {
  24. // Maps Carbon operator interface and operator names to Clang operator kinds.
  25. static auto GetClangOperatorKind(Context& context, SemIR::LocId loc_id,
  26. CoreIdentifier interface_name,
  27. CoreIdentifier op_name)
  28. -> std::optional<clang::OverloadedOperatorKind> {
  29. switch (interface_name) {
  30. // Unary operators.
  31. case CoreIdentifier::Destroy:
  32. case CoreIdentifier::As:
  33. case CoreIdentifier::ImplicitAs:
  34. case CoreIdentifier::UnsafeAs:
  35. case CoreIdentifier::Copy: {
  36. // TODO: Support destructors and conversions.
  37. return std::nullopt;
  38. }
  39. // Increment and decrement.
  40. case CoreIdentifier::Inc: {
  41. CARBON_CHECK(op_name == CoreIdentifier::Op);
  42. return clang::OO_PlusPlus;
  43. }
  44. case CoreIdentifier::Dec: {
  45. CARBON_CHECK(op_name == CoreIdentifier::Op);
  46. return clang::OO_MinusMinus;
  47. }
  48. // Arithmetic.
  49. case CoreIdentifier::Negate: {
  50. CARBON_CHECK(op_name == CoreIdentifier::Op);
  51. return clang::OO_Minus;
  52. }
  53. // Bitwise.
  54. case CoreIdentifier::BitComplement: {
  55. CARBON_CHECK(op_name == CoreIdentifier::Op);
  56. return clang::OO_Tilde;
  57. }
  58. // Binary operators.
  59. // Arithmetic operators.
  60. case CoreIdentifier::AddWith: {
  61. CARBON_CHECK(op_name == CoreIdentifier::Op);
  62. return clang::OO_Plus;
  63. }
  64. case CoreIdentifier::SubWith: {
  65. CARBON_CHECK(op_name == CoreIdentifier::Op);
  66. return clang::OO_Minus;
  67. }
  68. case CoreIdentifier::MulWith: {
  69. CARBON_CHECK(op_name == CoreIdentifier::Op);
  70. return clang::OO_Star;
  71. }
  72. case CoreIdentifier::DivWith: {
  73. CARBON_CHECK(op_name == CoreIdentifier::Op);
  74. return clang::OO_Slash;
  75. }
  76. case CoreIdentifier::ModWith: {
  77. CARBON_CHECK(op_name == CoreIdentifier::Op);
  78. return clang::OO_Percent;
  79. }
  80. // Bitwise operators.
  81. case CoreIdentifier::BitAndWith: {
  82. CARBON_CHECK(op_name == CoreIdentifier::Op);
  83. return clang::OO_Amp;
  84. }
  85. case CoreIdentifier::BitOrWith: {
  86. CARBON_CHECK(op_name == CoreIdentifier::Op);
  87. return clang::OO_Pipe;
  88. }
  89. case CoreIdentifier::BitXorWith: {
  90. CARBON_CHECK(op_name == CoreIdentifier::Op);
  91. return clang::OO_Caret;
  92. }
  93. case CoreIdentifier::LeftShiftWith: {
  94. CARBON_CHECK(op_name == CoreIdentifier::Op);
  95. return clang::OO_LessLess;
  96. }
  97. case CoreIdentifier::RightShiftWith: {
  98. CARBON_CHECK(op_name == CoreIdentifier::Op);
  99. return clang::OO_GreaterGreater;
  100. }
  101. // Assignment.
  102. case CoreIdentifier::AssignWith: {
  103. // TODO: This is not yet reached because we don't use the `AssignWith`
  104. // interface for assignment yet.
  105. CARBON_CHECK(op_name == CoreIdentifier::Op);
  106. return clang::OO_Equal;
  107. }
  108. // Compound assignment arithmetic operators.
  109. case CoreIdentifier::AddAssignWith: {
  110. CARBON_CHECK(op_name == CoreIdentifier::Op);
  111. return clang::OO_PlusEqual;
  112. }
  113. case CoreIdentifier::SubAssignWith: {
  114. CARBON_CHECK(op_name == CoreIdentifier::Op);
  115. return clang::OO_MinusEqual;
  116. }
  117. case CoreIdentifier::MulAssignWith: {
  118. CARBON_CHECK(op_name == CoreIdentifier::Op);
  119. return clang::OO_StarEqual;
  120. }
  121. case CoreIdentifier::DivAssignWith: {
  122. CARBON_CHECK(op_name == CoreIdentifier::Op);
  123. return clang::OO_SlashEqual;
  124. }
  125. case CoreIdentifier::ModAssignWith: {
  126. CARBON_CHECK(op_name == CoreIdentifier::Op);
  127. return clang::OO_PercentEqual;
  128. }
  129. // Compound assignment bitwise operators.
  130. case CoreIdentifier::BitAndAssignWith: {
  131. CARBON_CHECK(op_name == CoreIdentifier::Op);
  132. return clang::OO_AmpEqual;
  133. }
  134. case CoreIdentifier::BitOrAssignWith: {
  135. CARBON_CHECK(op_name == CoreIdentifier::Op);
  136. return clang::OO_PipeEqual;
  137. }
  138. case CoreIdentifier::BitXorAssignWith: {
  139. CARBON_CHECK(op_name == CoreIdentifier::Op);
  140. return clang::OO_CaretEqual;
  141. }
  142. case CoreIdentifier::LeftShiftAssignWith: {
  143. CARBON_CHECK(op_name == CoreIdentifier::Op);
  144. return clang::OO_LessLessEqual;
  145. }
  146. case CoreIdentifier::RightShiftAssignWith: {
  147. CARBON_CHECK(op_name == CoreIdentifier::Op);
  148. return clang::OO_GreaterGreaterEqual;
  149. }
  150. // Relational operators.
  151. case CoreIdentifier::EqWith: {
  152. if (op_name == CoreIdentifier::Equal) {
  153. return clang::OO_EqualEqual;
  154. }
  155. CARBON_CHECK(op_name == CoreIdentifier::NotEqual);
  156. return clang::OO_ExclaimEqual;
  157. }
  158. case CoreIdentifier::OrderedWith: {
  159. switch (op_name) {
  160. case CoreIdentifier::Less:
  161. return clang::OO_Less;
  162. case CoreIdentifier::Greater:
  163. return clang::OO_Greater;
  164. case CoreIdentifier::LessOrEquivalent:
  165. return clang::OO_LessEqual;
  166. case CoreIdentifier::GreaterOrEquivalent:
  167. return clang::OO_GreaterEqual;
  168. default:
  169. CARBON_FATAL("Unexpected OrderedWith op `{0}`", op_name);
  170. }
  171. }
  172. // Array indexing.
  173. case CoreIdentifier::IndexWith: {
  174. CARBON_CHECK(op_name == CoreIdentifier::At);
  175. return clang::OO_Subscript;
  176. }
  177. default: {
  178. context.TODO(loc_id, llvm::formatv("Unsupported operator interface `{0}`",
  179. interface_name));
  180. return std::nullopt;
  181. }
  182. }
  183. }
  184. // Creates and returns a function that can be used to construct a
  185. // std::initializer_list from an array.
  186. //
  187. // TODO: This should ideally be implemented in Carbon code rather than by
  188. // synthesizing a function.
  189. // TODO: We should cache and reuse the generated function.
  190. static auto MakeCppStdInitializerListMake(Context& context, SemIR::LocId loc_id,
  191. clang::QualType init_list_type,
  192. int32_t size) -> SemIR::InstId {
  193. // Extract the element type `T` from the `std::initializer_list<T>` type.
  194. clang::QualType element_type;
  195. bool is_std_initializer_list =
  196. context.clang_sema().isStdInitializerList(init_list_type, &element_type);
  197. CARBON_CHECK(is_std_initializer_list);
  198. auto element_type_inst_id =
  199. ImportCppType(context, loc_id, element_type).inst_id;
  200. if (element_type_inst_id == SemIR::ErrorInst::InstId) {
  201. return SemIR::ErrorInst::InstId;
  202. }
  203. // Import the `std::initializer_list<T>` type and check we recognize its
  204. // layout.
  205. auto [init_list_type_inst_id, init_list_type_id] =
  206. ImportCppType(context, loc_id, init_list_type);
  207. if (init_list_type_id == SemIR::ErrorInst::TypeId) {
  208. return SemIR::ErrorInst::InstId;
  209. }
  210. auto layout =
  211. SemIR::GetStdInitializerListLayout(context.sem_ir(), init_list_type_id);
  212. if (layout.kind == SemIR::StdInitializerListLayout::None) {
  213. context.TODO(loc_id, "Unsupported layout for std::initializer_list");
  214. return SemIR::ErrorInst::InstId;
  215. }
  216. auto init_list_class_id = context.sem_ir()
  217. .types()
  218. .GetAs<SemIR::ClassType>(init_list_type_id)
  219. .class_id;
  220. auto& init_list_class = context.classes().Get(init_list_class_id);
  221. // Build the array type `T[size]` that we use as the parameter type.
  222. // TODO: This will eventually be called from impl lookup, possibly while
  223. // forming a specific, so we should not be adding instructions here.
  224. auto bound_id = AddInst(
  225. context, SemIR::LocIdAndInst(
  226. loc_id, SemIR::IntValue{
  227. .type_id = GetSingletonType(
  228. context, SemIR::IntLiteralType::TypeInstId),
  229. .int_id = context.ints().Add(size)}));
  230. auto array_type_inst_id = AddTypeInst(
  231. context, SemIR::LocIdAndInst::UncheckedLoc(
  232. loc_id, SemIR::ArrayType{
  233. .type_id = SemIR::TypeType::TypeId,
  234. .bound_id = bound_id,
  235. .element_type_inst_id = element_type_inst_id}));
  236. auto array_type_id =
  237. context.types().GetTypeIdForTypeInstId(array_type_inst_id);
  238. // Create a builtin function to perform the conversion from array type to
  239. // initializer list type. We name the synthesized function as if it were a
  240. // constructor of std::initializer_list.
  241. // TODO: Find a better way to handle this. Ideally we should stop using this
  242. // function entirely and declare the necessary builtin in the prelude.
  243. auto [decl_id, function_id] =
  244. MakeGeneratedFunctionDecl(context, loc_id,
  245. {.parent_scope_id = init_list_class.scope_id,
  246. .name_id = init_list_class.name_id,
  247. .param_type_ids = {array_type_id},
  248. .return_type_id = init_list_type_id});
  249. auto& function = context.functions().Get(function_id);
  250. CARBON_CHECK(IsValidBuiltinDeclaration(
  251. context, function,
  252. SemIR::BuiltinFunctionKind::CppStdInitializerListMake));
  253. function.SetBuiltinFunction(
  254. SemIR::BuiltinFunctionKind::CppStdInitializerListMake);
  255. return decl_id;
  256. }
  257. // Returns information about the Carbon signature to import when importing a C++
  258. // constructor or conversion operator.
  259. static auto GetConversionSignatureToImport(
  260. Context& context, SemIR::InstId source_id,
  261. clang::InitializationSequence::StepKind step_kind,
  262. clang::FunctionDecl* function_decl) -> SemIR::ClangDeclKey::Signature {
  263. // If we're performing a constructor initialization from a list, form a
  264. // function signature that takes a single tuple or struct pattern
  265. // instead of a function signature with one parameter per C++ parameter.
  266. if (step_kind ==
  267. clang::InitializationSequence::SK_ConstructorInitializationFromList) {
  268. // The source type should always be a tuple type, because we don't support
  269. // C++ initialization from struct types.
  270. auto tuple_type = context.types().TryGetAs<SemIR::TupleType>(
  271. context.insts().Get(source_id).type_id());
  272. CARBON_CHECK(tuple_type, "List initialization from non-tuple type");
  273. // Initialization from a tuple `(a, b, c)` results in a constructor
  274. // function that takes a tuple pattern:
  275. //
  276. // fn Class.Class((a: A, b: B, c: C)) -> Class;
  277. return {
  278. .kind = SemIR::ClangDeclKey::Signature::Kind::TuplePattern,
  279. .num_params = static_cast<int32_t>(
  280. context.inst_blocks().Get(tuple_type->type_elements_id).size())};
  281. }
  282. // Any other initialization using a constructor is calling a converting
  283. // constructor:
  284. //
  285. // fn Class.Class(a: A) -> Class;
  286. if (isa<clang::CXXConstructorDecl>(function_decl)) {
  287. return {.kind = SemIR::ClangDeclKey::Signature::Kind::Normal,
  288. .num_params = 1};
  289. }
  290. // Otherwise, the initialization is calling a conversion function
  291. // `Source::operator Dest`:
  292. //
  293. // fn Source.<conversion function>[self: Source]() -> Dest;
  294. CARBON_CHECK(isa<clang::CXXConversionDecl>(function_decl));
  295. return {.kind = SemIR::ClangDeclKey::Signature::Kind::Normal,
  296. .num_params = 0};
  297. }
  298. static auto LookupCppConversion(Context& context, SemIR::LocId loc_id,
  299. SemIR::InstId source_id,
  300. SemIR::TypeId dest_type_id, bool allow_explicit)
  301. -> SemIR::InstId {
  302. if (context.types().Is<SemIR::StructType>(
  303. context.insts().Get(source_id).type_id())) {
  304. // Structs can only be used to initialize C++ aggregates. That case is
  305. // handled by Convert, not here.
  306. return SemIR::InstId::None;
  307. }
  308. auto dest_type = MapToCppType(context, dest_type_id);
  309. if (dest_type.isNull()) {
  310. return SemIR::InstId::None;
  311. }
  312. auto* arg_expr = InventClangArg(context, source_id);
  313. // If we can't map the argument, we can't perform the conversion.
  314. if (!arg_expr) {
  315. return SemIR::InstId::None;
  316. }
  317. auto loc = GetCppLocation(context, loc_id);
  318. // Form a Clang initialization sequence.
  319. auto& sema = context.clang_sema();
  320. clang::InitializedEntity entity =
  321. clang::InitializedEntity::InitializeTemporary(dest_type);
  322. clang::InitializationKind kind =
  323. allow_explicit ? clang::InitializationKind::CreateDirect(
  324. loc, /*LParenLoc=*/clang::SourceLocation(),
  325. /*RParenLoc=*/clang::SourceLocation())
  326. : clang::InitializationKind::CreateCopy(
  327. loc, /*EqualLoc=*/clang::SourceLocation());
  328. clang::MultiExprArg args(arg_expr);
  329. // `(a, b) as T` uses `T{a, b}`, not `T({a, b})`. The latter would introduce
  330. // a redundant extra copy.
  331. // TODO: We need to communicate this back to the caller so they know to call
  332. // the constructor with an exploded argument list somehow.
  333. if (allow_explicit && isa<clang::InitListExpr>(arg_expr)) {
  334. kind = clang::InitializationKind::CreateDirectList(loc);
  335. }
  336. clang::InitializationSequence init(sema, entity, kind, args);
  337. if (init.Failed()) {
  338. // TODO: Are there initialization failures that we should translate into
  339. // errors rather than a missing conversion?
  340. return SemIR::InstId::None;
  341. }
  342. // Scan the steps looking for user-defined conversions. For now we just find
  343. // and return the first such conversion function. We skip over standard
  344. // conversions; we'll perform those using the Carbon rules as part of calling
  345. // the C++ conversion function.
  346. for (const auto& step : init.steps()) {
  347. switch (step.Kind) {
  348. case clang::InitializationSequence::SK_UserConversion:
  349. case clang::InitializationSequence::SK_ConstructorInitialization:
  350. case clang::InitializationSequence::SK_StdInitializerListConstructorCall:
  351. case clang::InitializationSequence::
  352. SK_ConstructorInitializationFromList: {
  353. if (auto* ctor =
  354. dyn_cast<clang::CXXConstructorDecl>(step.Function.Function);
  355. ctor && ctor->isCopyOrMoveConstructor()) {
  356. // Skip copy / move constructor calls. They shouldn't be performed
  357. // this way because they're not considered conversions in Carbon, and
  358. // will frequently lead to infinite recursion because we'll end up
  359. // back here when attempting to convert the argument.
  360. continue;
  361. }
  362. if (sema.DiagnoseUseOfOverloadedDecl(step.Function.Function, loc)) {
  363. return SemIR::ErrorInst::InstId;
  364. }
  365. sema.MarkFunctionReferenced(loc, step.Function.Function);
  366. auto signature = GetConversionSignatureToImport(
  367. context, source_id, step.Kind, step.Function.Function);
  368. auto result_id = ImportCppFunctionDecl(
  369. context, loc_id, step.Function.Function, signature);
  370. if (auto fn_decl = context.insts().TryGetAsWithId<SemIR::FunctionDecl>(
  371. result_id)) {
  372. CheckCppOverloadAccess(context, loc_id, step.Function.FoundDecl,
  373. fn_decl->inst_id);
  374. } else {
  375. CARBON_CHECK(result_id == SemIR::ErrorInst::InstId);
  376. }
  377. // TODO: There may be other conversions later in the sequence that we
  378. // need to model; we've only applied the first one here.
  379. return result_id;
  380. }
  381. case clang::InitializationSequence::SK_StdInitializerList: {
  382. return MakeCppStdInitializerListMake(
  383. context, loc_id, step.Type,
  384. cast<clang::InitListExpr>(arg_expr)->getNumInits());
  385. }
  386. case clang::InitializationSequence::SK_ListInitialization: {
  387. // Aggregate initialization is handled by the normal Carbon conversion
  388. // logic, so we ignore it here.
  389. // TODO: So far we only support aggregate initialization for arrays and
  390. // empty classes.
  391. continue;
  392. }
  393. case clang::InitializationSequence::SK_ConversionSequence:
  394. case clang::InitializationSequence::SK_ConversionSequenceNoNarrowing: {
  395. // Implicit conversions are handled by the normal Carbon conversion
  396. // logic, so we ignore them here.
  397. continue;
  398. }
  399. default: {
  400. // TODO: Handle other kinds of initialization steps. For now we assume
  401. // they will be handled by our function call logic and we can skip them.
  402. RawStringOstream os;
  403. os << "Unsupported initialization sequence:\n";
  404. init.dump(os);
  405. context.TODO(loc_id, os.TakeStr());
  406. return SemIR::ErrorInst::InstId;
  407. }
  408. }
  409. }
  410. return SemIR::InstId::None;
  411. }
  412. auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
  413. llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
  414. // Register an annotation scope to flush any Clang diagnostics when we return.
  415. // This is important to ensure that Clang diagnostics are properly interleaved
  416. // with Carbon diagnostics.
  417. Diagnostics::AnnotationScope annotate_diagnostics(&context.emitter(),
  418. [](auto& /*builder*/) {});
  419. // Handle `ImplicitAs` and `As`.
  420. if (op.interface_name == CoreIdentifier::ImplicitAs ||
  421. op.interface_name == CoreIdentifier::As) {
  422. if (op.interface_args_ref.size() != 1 || arg_ids.size() != 1) {
  423. return SemIR::InstId::None;
  424. }
  425. // The argument is the destination type for both interfaces.
  426. auto dest_const_id =
  427. context.constant_values().Get(op.interface_args_ref[0]);
  428. auto dest_type_id =
  429. context.types().TryGetTypeIdForTypeConstantId(dest_const_id);
  430. if (!dest_type_id.has_value()) {
  431. return SemIR::InstId::None;
  432. }
  433. return LookupCppConversion(
  434. context, loc_id, arg_ids[0], dest_type_id,
  435. /*allow_explicit=*/op.interface_name == CoreIdentifier::As);
  436. }
  437. auto op_kind =
  438. GetClangOperatorKind(context, loc_id, op.interface_name, op.op_name);
  439. if (!op_kind) {
  440. return SemIR::InstId::None;
  441. }
  442. // Make sure all operands are complete before lookup.
  443. for (SemIR::InstId arg_id : arg_ids) {
  444. SemIR::TypeId arg_type_id = context.insts().Get(arg_id).type_id();
  445. if (!RequireCompleteType(context, arg_type_id, loc_id, [&](auto& builder) {
  446. CARBON_DIAGNOSTIC(
  447. IncompleteOperandTypeInCppOperatorLookup, Context,
  448. "looking up a C++ operator with incomplete operand type {0}",
  449. SemIR::TypeId);
  450. builder.Context(loc_id, IncompleteOperandTypeInCppOperatorLookup,
  451. arg_type_id);
  452. })) {
  453. return SemIR::ErrorInst::InstId;
  454. }
  455. }
  456. auto maybe_arg_exprs = InventClangArgs(context, arg_ids);
  457. if (!maybe_arg_exprs.has_value()) {
  458. return SemIR::ErrorInst::InstId;
  459. }
  460. auto& arg_exprs = *maybe_arg_exprs;
  461. clang::SourceLocation loc = GetCppLocation(context, loc_id);
  462. clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
  463. *op_kind, loc, /*AllowRewritten=*/true);
  464. clang::OverloadCandidateSet candidate_set(
  465. loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
  466. clang::Sema& sema = context.clang_sema();
  467. // This works for both unary and binary operators.
  468. sema.LookupOverloadedBinOp(candidate_set, *op_kind, clang::UnresolvedSet<0>{},
  469. arg_exprs);
  470. clang::OverloadCandidateSet::iterator best_viable_fn;
  471. switch (candidate_set.BestViableFunction(sema, loc, best_viable_fn)) {
  472. case clang::OverloadingResult::OR_Success: {
  473. if (!best_viable_fn->Function) {
  474. // The best viable candidate was a builtin. Let the Carbon operator
  475. // machinery handle that.
  476. return SemIR::InstId::None;
  477. }
  478. if (best_viable_fn->RewriteKind) {
  479. context.TODO(
  480. loc_id,
  481. llvm::formatv("Rewriting operator{0} using {1} is not supported",
  482. clang::getOperatorSpelling(
  483. candidate_set.getRewriteInfo().OriginalOperator),
  484. best_viable_fn->Function->getNameAsString()));
  485. return SemIR::ErrorInst::InstId;
  486. }
  487. sema.MarkFunctionReferenced(loc, best_viable_fn->Function);
  488. // If this is an operator method, the first arg will be used as self.
  489. int32_t num_params = arg_ids.size();
  490. if (isa<clang::CXXMethodDecl>(best_viable_fn->Function)) {
  491. --num_params;
  492. }
  493. auto result_id =
  494. ImportCppFunctionDecl(context, loc_id, best_viable_fn->Function,
  495. {.num_params = num_params});
  496. if (result_id != SemIR::ErrorInst::InstId) {
  497. CheckCppOverloadAccess(
  498. context, loc_id, best_viable_fn->FoundDecl,
  499. context.insts().GetAsKnownInstId<SemIR::FunctionDecl>(result_id));
  500. }
  501. return result_id;
  502. }
  503. case clang::OverloadingResult::OR_No_Viable_Function: {
  504. // OK, didn't find a viable C++ candidate, but this is not an error, as
  505. // there might be a Carbon candidate.
  506. return SemIR::InstId::None;
  507. }
  508. case clang::OverloadingResult::OR_Ambiguous: {
  509. const char* spelling = clang::getOperatorSpelling(*op_kind);
  510. candidate_set.NoteCandidates(
  511. clang::PartialDiagnosticAt(
  512. loc, sema.PDiag(clang::diag::err_ovl_ambiguous_oper_binary)
  513. << spelling << arg_exprs[0]->getType()
  514. << arg_exprs[1]->getType()),
  515. sema, clang::OCD_AmbiguousCandidates, arg_exprs, spelling, loc);
  516. return SemIR::ErrorInst::InstId;
  517. }
  518. case clang::OverloadingResult::OR_Deleted:
  519. const char* spelling = clang::getOperatorSpelling(*op_kind);
  520. auto* message = best_viable_fn->Function->getDeletedMessage();
  521. // The best viable function might be a different operator if the best
  522. // candidate is a rewritten candidate, so use the operator kind of the
  523. // candidate itself in the diagnostic.
  524. candidate_set.NoteCandidates(
  525. clang::PartialDiagnosticAt(
  526. loc, sema.PDiag(clang::diag::err_ovl_deleted_oper)
  527. << clang::getOperatorSpelling(
  528. best_viable_fn->Function->getOverloadedOperator())
  529. << (message != nullptr)
  530. << (message ? message->getString() : llvm::StringRef())),
  531. sema, clang::OCD_AllCandidates, arg_exprs, spelling, loc);
  532. return SemIR::ErrorInst::InstId;
  533. }
  534. }
  535. auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
  536. auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
  537. return clang_method_decl &&
  538. (clang_method_decl->isOverloadedOperator() ||
  539. isa<clang::CXXConversionDecl>(clang_method_decl));
  540. }
  541. static auto GetAsCppFunctionDecl(Context& context, SemIR::InstId inst_id)
  542. -> clang::FunctionDecl* {
  543. if (inst_id == SemIR::InstId::None) {
  544. return nullptr;
  545. }
  546. auto function_type = context.types().TryGetAs<SemIR::FunctionType>(
  547. context.insts().Get(inst_id).type_id());
  548. if (!function_type) {
  549. return nullptr;
  550. }
  551. SemIR::ClangDeclId clang_decl_id =
  552. context.functions().Get(function_type->function_id).clang_decl_id;
  553. return clang_decl_id.has_value()
  554. ? dyn_cast<clang::FunctionDecl>(
  555. context.clang_decls().Get(clang_decl_id).key.decl)
  556. : nullptr;
  557. }
  558. auto IsCppOperatorMethod(Context& context, SemIR::InstId inst_id) -> bool {
  559. auto* function_decl = GetAsCppFunctionDecl(context, inst_id);
  560. return function_decl && IsCppOperatorMethodDecl(function_decl);
  561. }
  562. auto IsCppConstructorOrNonMethodOperator(Context& context,
  563. SemIR::InstId inst_id) -> bool {
  564. auto* function_decl = GetAsCppFunctionDecl(context, inst_id);
  565. if (!function_decl) {
  566. return false;
  567. }
  568. if (isa<clang::CXXConstructorDecl>(function_decl)) {
  569. return true;
  570. }
  571. return !isa<clang::CXXMethodDecl>(function_decl) &&
  572. function_decl->isOverloadedOperator();
  573. }
  574. } // namespace Carbon::Check