operators.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  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/Overload.h"
  6. #include "clang/Sema/Sema.h"
  7. #include "toolchain/check/cpp/import.h"
  8. #include "toolchain/check/cpp/location.h"
  9. #include "toolchain/check/cpp/type_mapping.h"
  10. #include "toolchain/check/inst.h"
  11. #include "toolchain/check/type.h"
  12. #include "toolchain/check/type_completion.h"
  13. #include "toolchain/sem_ir/ids.h"
  14. namespace Carbon::Check {
  15. // Maps Carbon operator interface and operator names to Clang operator kinds.
  16. static auto GetClangOperatorKind(Context& context, SemIR::LocId loc_id,
  17. llvm::StringLiteral interface_name,
  18. llvm::StringLiteral op_name)
  19. -> std::optional<clang::OverloadedOperatorKind> {
  20. // Unary operators.
  21. if (interface_name == "Destroy" || interface_name == "As" ||
  22. interface_name == "ImplicitAs") {
  23. // TODO: Support destructors and conversions.
  24. return std::nullopt;
  25. }
  26. // Increment and Decrement.
  27. if (interface_name == "Inc") {
  28. CARBON_CHECK(op_name == "Op");
  29. return clang::OO_PlusPlus;
  30. }
  31. if (interface_name == "Dec") {
  32. CARBON_CHECK(op_name == "Op");
  33. return clang::OO_MinusMinus;
  34. }
  35. // Arithmetic.
  36. if (interface_name == "Negate") {
  37. CARBON_CHECK(op_name == "Op");
  38. return clang::OO_Minus;
  39. }
  40. // Binary operators.
  41. // Arithmetic Operators.
  42. if (interface_name == "AddWith") {
  43. CARBON_CHECK(op_name == "Op");
  44. return clang::OO_Plus;
  45. }
  46. if (interface_name == "SubWith") {
  47. CARBON_CHECK(op_name == "Op");
  48. return clang::OO_Minus;
  49. }
  50. if (interface_name == "MulWith") {
  51. CARBON_CHECK(op_name == "Op");
  52. return clang::OO_Star;
  53. }
  54. if (interface_name == "DivWith") {
  55. CARBON_CHECK(op_name == "Op");
  56. return clang::OO_Slash;
  57. }
  58. if (interface_name == "ModWith") {
  59. CARBON_CHECK(op_name == "Op");
  60. return clang::OO_Percent;
  61. }
  62. // Bitwise Operators.
  63. if (interface_name == "BitAndWith") {
  64. CARBON_CHECK(op_name == "Op");
  65. return clang::OO_Amp;
  66. }
  67. if (interface_name == "BitOrWith") {
  68. CARBON_CHECK(op_name == "Op");
  69. return clang::OO_Pipe;
  70. }
  71. if (interface_name == "BitXorWith") {
  72. CARBON_CHECK(op_name == "Op");
  73. return clang::OO_Caret;
  74. }
  75. if (interface_name == "LeftShiftWith") {
  76. CARBON_CHECK(op_name == "Op");
  77. return clang::OO_LessLess;
  78. }
  79. if (interface_name == "RightShiftWith") {
  80. CARBON_CHECK(op_name == "Op");
  81. return clang::OO_GreaterGreater;
  82. }
  83. // Compound Assignment Arithmetic Operators.
  84. if (interface_name == "AddAssignWith") {
  85. CARBON_CHECK(op_name == "Op");
  86. return clang::OO_PlusEqual;
  87. }
  88. if (interface_name == "SubAssignWith") {
  89. CARBON_CHECK(op_name == "Op");
  90. return clang::OO_MinusEqual;
  91. }
  92. if (interface_name == "MulAssignWith") {
  93. CARBON_CHECK(op_name == "Op");
  94. return clang::OO_StarEqual;
  95. }
  96. if (interface_name == "DivAssignWith") {
  97. CARBON_CHECK(op_name == "Op");
  98. return clang::OO_SlashEqual;
  99. }
  100. if (interface_name == "ModAssignWith") {
  101. CARBON_CHECK(op_name == "Op");
  102. return clang::OO_PercentEqual;
  103. }
  104. // Compound Assignment Bitwise Operators.
  105. if (interface_name == "BitAndAssignWith") {
  106. CARBON_CHECK(op_name == "Op");
  107. return clang::OO_AmpEqual;
  108. }
  109. if (interface_name == "BitOrAssignWith") {
  110. CARBON_CHECK(op_name == "Op");
  111. return clang::OO_PipeEqual;
  112. }
  113. if (interface_name == "BitXorAssignWith") {
  114. CARBON_CHECK(op_name == "Op");
  115. return clang::OO_CaretEqual;
  116. }
  117. if (interface_name == "LeftShiftAssignWith") {
  118. CARBON_CHECK(op_name == "Op");
  119. return clang::OO_LessLessEqual;
  120. }
  121. if (interface_name == "RightShiftAssignWith") {
  122. CARBON_CHECK(op_name == "Op");
  123. return clang::OO_GreaterGreaterEqual;
  124. }
  125. // Relational Operators.
  126. if (interface_name == "EqWith") {
  127. if (op_name == "Equal") {
  128. return clang::OO_EqualEqual;
  129. }
  130. CARBON_CHECK(op_name == "NotEqual");
  131. return clang::OO_ExclaimEqual;
  132. }
  133. if (interface_name == "OrderedWith") {
  134. if (op_name == "Less") {
  135. return clang::OO_Less;
  136. }
  137. if (op_name == "Greater") {
  138. return clang::OO_Greater;
  139. }
  140. if (op_name == "LessOrEquivalent") {
  141. return clang::OO_LessEqual;
  142. }
  143. CARBON_CHECK(op_name == "GreaterOrEquivalent");
  144. return clang::OO_GreaterEqual;
  145. }
  146. context.TODO(loc_id, llvm::formatv("Unsupported operator interface `{0}`",
  147. interface_name));
  148. return std::nullopt;
  149. }
  150. auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
  151. llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
  152. // Register an annotation scope to flush any Clang diagnostics when we return.
  153. // This is important to ensure that Clang diagnostics are properly interleaved
  154. // with Carbon diagnostics.
  155. Diagnostics::AnnotationScope annotate_diagnostics(&context.emitter(),
  156. [](auto& /*builder*/) {});
  157. auto op_kind =
  158. GetClangOperatorKind(context, loc_id, op.interface_name, op.op_name);
  159. if (!op_kind) {
  160. return SemIR::InstId::None;
  161. }
  162. // Make sure all operands are complete before lookup.
  163. for (SemIR::InstId arg_id : arg_ids) {
  164. SemIR::TypeId arg_type_id = context.insts().Get(arg_id).type_id();
  165. if (!RequireCompleteType(context, arg_type_id, loc_id, [&] {
  166. CARBON_DIAGNOSTIC(
  167. IncompleteOperandTypeInCppOperatorLookup, Error,
  168. "looking up a C++ operator with incomplete operand type {0}",
  169. SemIR::TypeId);
  170. return context.emitter().Build(
  171. loc_id, IncompleteOperandTypeInCppOperatorLookup, arg_type_id);
  172. })) {
  173. return SemIR::ErrorInst::InstId;
  174. }
  175. }
  176. auto arg_exprs = InventClangArgs(context, arg_ids);
  177. if (!arg_exprs.has_value()) {
  178. return SemIR::ErrorInst::InstId;
  179. }
  180. clang::SourceLocation loc = GetCppLocation(context, loc_id);
  181. clang::OverloadCandidateSet::OperatorRewriteInfo operator_rewrite_info(
  182. *op_kind, loc, /*AllowRewritten=*/true);
  183. clang::UnresolvedSet<4> functions;
  184. clang::OverloadCandidateSet candidate_set(
  185. loc, clang::OverloadCandidateSet::CSK_Operator, operator_rewrite_info);
  186. // This works for both unary and binary operators.
  187. context.clang_sema().LookupOverloadedBinOp(candidate_set, *op_kind, functions,
  188. *arg_exprs);
  189. for (auto& it : candidate_set) {
  190. if (!it.Function) {
  191. continue;
  192. }
  193. functions.addDecl(it.Function, it.FoundDecl.getAccess());
  194. }
  195. return ImportCppOverloadSet(
  196. context, loc_id, SemIR::NameScopeId::None, SemIR::NameId::CppOperator,
  197. /*naming_class=*/nullptr, std::move(functions), operator_rewrite_info);
  198. }
  199. auto IsCppOperatorMethodDecl(clang::Decl* decl) -> bool {
  200. auto* clang_method_decl = dyn_cast<clang::CXXMethodDecl>(decl);
  201. return clang_method_decl && clang_method_decl->isOverloadedOperator();
  202. }
  203. } // namespace Carbon::Check