| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- // Exceptions. See /LICENSE for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- #include "toolchain/check/cpp/operators.h"
- #include "clang/Sema/Overload.h"
- #include "clang/Sema/Sema.h"
- #include "toolchain/check/cpp/import.h"
- #include "toolchain/check/cpp/type_mapping.h"
- #include "toolchain/check/inst.h"
- #include "toolchain/check/type.h"
- #include "toolchain/check/type_completion.h"
- #include "toolchain/sem_ir/ids.h"
- namespace Carbon::Check {
- // Maps Carbon operator interface and operator names to Clang operator kinds.
- static auto GetClangOperatorKind(Context& context, SemIR::LocId loc_id,
- llvm::StringLiteral interface_name,
- llvm::StringLiteral op_name)
- -> std::optional<clang::OverloadedOperatorKind> {
- // Unary operators.
- if (interface_name == "Destroy" || interface_name == "As" ||
- interface_name == "ImplicitAs") {
- // TODO: Support destructors and conversions.
- return std::nullopt;
- }
- // Increment and Decrement.
- if (interface_name == "Inc") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_PlusPlus;
- }
- if (interface_name == "Dec") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_MinusMinus;
- }
- // Arithmetic.
- if (interface_name == "Negate") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Minus;
- }
- // Binary operators.
- // Arithmetic Operators.
- if (interface_name == "AddWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Plus;
- }
- if (interface_name == "SubWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Minus;
- }
- if (interface_name == "MulWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Star;
- }
- if (interface_name == "DivWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Slash;
- }
- if (interface_name == "ModWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Percent;
- }
- // Bitwise Operators.
- if (interface_name == "BitAndWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Amp;
- }
- if (interface_name == "BitOrWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Pipe;
- }
- if (interface_name == "BitXorWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_Caret;
- }
- if (interface_name == "LeftShiftWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_LessLess;
- }
- if (interface_name == "RightShiftWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_GreaterGreater;
- }
- // Compound Assignment Arithmetic Operators.
- if (interface_name == "AddAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_PlusEqual;
- }
- if (interface_name == "SubAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_MinusEqual;
- }
- if (interface_name == "MulAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_StarEqual;
- }
- if (interface_name == "DivAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_SlashEqual;
- }
- if (interface_name == "ModAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_PercentEqual;
- }
- // Compound Assignment Bitwise Operators.
- if (interface_name == "BitAndAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_AmpEqual;
- }
- if (interface_name == "BitOrAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_PipeEqual;
- }
- if (interface_name == "BitXorAssignWith") {
- CARBON_CHECK(op_name == "Op");
- return clang::OO_CaretEqual;
- }
- // TODO: Add support for `LeftShiftAssignWith` (`OO_LessLessEqual`) and
- // `RightShiftAssignWith` (`OO_GreaterGreaterEqual`) when references are
- // supported.
- // Relational Operators.
- if (interface_name == "EqWith") {
- if (op_name == "Equal") {
- return clang::OO_EqualEqual;
- }
- CARBON_CHECK(op_name == "NotEqual");
- return clang::OO_ExclaimEqual;
- }
- if (interface_name == "OrderedWith") {
- if (op_name == "Less") {
- return clang::OO_Less;
- }
- if (op_name == "Greater") {
- return clang::OO_Greater;
- }
- if (op_name == "LessOrEquivalent") {
- return clang::OO_LessEqual;
- }
- CARBON_CHECK(op_name == "GreaterOrEquivalent");
- return clang::OO_GreaterEqual;
- }
- context.TODO(loc_id, llvm::formatv("Unsupported operator interface `{0}`",
- interface_name));
- return std::nullopt;
- }
- auto LookupCppOperator(Context& context, SemIR::LocId loc_id, Operator op,
- llvm::ArrayRef<SemIR::InstId> arg_ids) -> SemIR::InstId {
- Diagnostics::AnnotationScope annotate_diagnostics(
- &context.emitter(), [&](auto& builder) {
- CARBON_DIAGNOSTIC(InCppOperatorLookup, Note,
- "in `Cpp` operator `{0}` lookup", std::string);
- builder.Note(loc_id, InCppOperatorLookup, op.interface_name.str());
- });
- auto op_kind =
- GetClangOperatorKind(context, loc_id, op.interface_name, op.op_name);
- if (!op_kind) {
- 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::UnresolvedSet<4> functions;
- // TODO: Add location accordingly.
- clang::OverloadCandidateSet candidate_set(
- clang::SourceLocation(), clang::OverloadCandidateSet::CSK_Operator);
- // 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));
- }
- } // namespace Carbon::Check
|