operators.cpp 20 KB

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