operators.cpp 28 KB

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