diff --git a/core/prelude/iterate.carbon b/core/prelude/iterate.carbon index b5081091c238..9f4024674cf9 100644 --- a/core/prelude/iterate.carbon +++ b/core/prelude/iterate.carbon @@ -30,3 +30,10 @@ impl forall [T:! Copy & Destroy, N:! IntLiteral()] } } } + +interface CppRangeForIterate { + let Iterator:! type; + let Sentinel:! type; + fn Begin[ref self: Self]() -> Iterator; + fn End[ref self: Self]() -> Sentinel; +} diff --git a/toolchain/check/core_identifier.def b/toolchain/check/core_identifier.def index 6d8fcd7a78ba..2d1e4374b735 100644 --- a/toolchain/check/core_identifier.def +++ b/toolchain/check/core_identifier.def @@ -33,6 +33,7 @@ CARBON_CORE_IDENTIFIER(Char) CARBON_CORE_IDENTIFIER(Convert) CARBON_CORE_IDENTIFIER(Copy) CARBON_CORE_IDENTIFIER(CppCompat) +CARBON_CORE_IDENTIFIER(CppRangeForIterate) CARBON_CORE_IDENTIFIER(CppUnsafeDeref) CARBON_CORE_IDENTIFIER(Dec) CARBON_CORE_IDENTIFIER(Default) diff --git a/toolchain/check/cpp/impl_lookup.cpp b/toolchain/check/cpp/impl_lookup.cpp index a21d75c8bb61..1bf521c20182 100644 --- a/toolchain/check/cpp/impl_lookup.cpp +++ b/toolchain/check/cpp/impl_lookup.cpp @@ -4,6 +4,8 @@ #include "toolchain/check/cpp/impl_lookup.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "toolchain/base/kind_switch.h" #include "toolchain/check/core_identifier.h" @@ -11,6 +13,7 @@ #include "toolchain/check/cpp/location.h" #include "toolchain/check/cpp/operators.h" #include "toolchain/check/cpp/overload_resolution.h" +#include "toolchain/check/cpp/type_mapping.h" #include "toolchain/check/custom_witness.h" #include "toolchain/check/impl.h" #include "toolchain/check/impl_lookup.h" @@ -353,6 +356,118 @@ static auto BuildCppComparisonWitness( query_specific_interface_id, operators); } +static auto LookupCppMethod( + Context& context, clang::Sema& clang_sema, SemIR::LocId loc_id, + const clang::DeclarationNameInfo& name_info, + clang::CXXRecordDecl* class_decl, + [[maybe_unused]] SemIR::ConstantId query_self_const_id) -> SemIR::InstId { + constexpr auto LookupKind = clang::Sema::LookupMemberName; + auto lookup_info = clang::LookupResult(clang_sema, name_info, LookupKind); + clang_sema.LookupQualifiedName(lookup_info, class_decl); + if (lookup_info.empty()) { + return SemIR::InstId::None; + } + + if (!lookup_info.isSingleResult()) { + context.TODO(loc_id, "{method_name} overload sets unsupported"); + return SemIR::ErrorInst::InstId; + } + + auto decl_info = DeclInfo{ + .decl = *lookup_info.begin(), + .signature = {.num_params = 0}, + }; + return GetFunctionId(context, loc_id, decl_info); +} + +static auto LookupCppUnqualified(Context& context, clang::Sema& clang_sema, + SemIR::LocId loc_id, + const clang::DeclarationNameInfo& name_info, + clang::CXXRecordDecl* class_decl, + SemIR::ConstantId query_self_const_id) + -> SemIR::InstId { + (void)clang_sema; + (void)name_info; + (void)class_decl; + (void)query_self_const_id; + context.TODO(loc_id, "support ADL begin/end"); + return SemIR::ErrorInst::InstId; +} + +using LookupBeginEndCallees = auto(Context&, clang::Sema&, SemIR::LocId, + const clang::DeclarationNameInfo&, + clang::CXXRecordDecl*, SemIR::ConstantId) + -> SemIR::InstId; + +static auto BuildCppRangeForIterateWitnessImpl( + Context& context, SemIR::LocId loc_id, + LookupBeginEndCallees range_for_lookup, clang::CXXRecordDecl* class_decl, + SemIR::ConstantId query_self_const_id, + SemIR::SpecificInterfaceId query_specific_interface_id) -> SemIR::InstId { + auto& clang_sema = context.clang_sema(); + auto begin_name_info = clang::DeclarationNameInfo( + &clang_sema.PP.getIdentifierTable().get("begin"), + clang::SourceLocation()); + auto begin_fn_id = + range_for_lookup(context, clang_sema, loc_id, begin_name_info, class_decl, + query_self_const_id); + if (begin_fn_id == SemIR::InstId::None || + begin_fn_id == SemIR::ErrorInst::InstId) { + return begin_fn_id; + } + + auto begin_result_type_id = + context.functions() + .Get(context.insts() + .GetAs(begin_fn_id) + .function_id) + .return_type_inst_id; + if (begin_result_type_id == SemIR::ErrorInst::InstId || + begin_result_type_id == SemIR::InstId::None) { + return SemIR::ErrorInst::InstId; + } + + auto end_name_info = clang::DeclarationNameInfo( + &clang_sema.PP.getIdentifierTable().get("end"), clang::SourceLocation()); + auto end_fn_id = range_for_lookup(context, clang_sema, loc_id, end_name_info, + class_decl, query_self_const_id); + if (end_fn_id == SemIR::InstId::None || + end_fn_id == SemIR::ErrorInst::InstId) { + return end_fn_id; + } + + auto end_result_type_id = + context.functions() + .Get( + context.insts().GetAs(end_fn_id).function_id) + .return_type_inst_id; + if (end_result_type_id == SemIR::ErrorInst::InstId || + end_result_type_id == SemIR::InstId::None) { + return SemIR::ErrorInst::InstId; + } + + return BuildCustomWitness( + context, loc_id, query_self_const_id, query_specific_interface_id, + {begin_result_type_id, end_result_type_id, begin_fn_id, end_fn_id}); +} + +static auto BuildCppRangeForIterateWitness( + Context& context, SemIR::LocId loc_id, + SemIR::ConstantId query_self_const_id, + SemIR::SpecificInterfaceId query_specific_interface_id) -> SemIR::InstId { + auto* class_decl = TypeAsClassDecl(context, query_self_const_id); + if (auto with_members = BuildCppRangeForIterateWitnessImpl( + context, loc_id, LookupCppMethod, class_decl, query_self_const_id, + query_specific_interface_id); + with_members != SemIR::InstId::None) { + return with_members; + } + + return BuildCppRangeForIterateWitnessImpl( + context, loc_id, LookupCppUnqualified, class_decl, query_self_const_id, + query_specific_interface_id); +} + auto LookupCppImpl(Context& context, SemIR::LocId loc_id, SemIR::CoreInterface core_interface, SemIR::ConstantId query_self_const_id, @@ -417,6 +532,10 @@ auto LookupCppImpl(Context& context, SemIR::LocId loc_id, return BuildDestroyWitness(context, loc_id, query_self_const_id, query_specific_interface_id); + case SemIR::CoreInterface::CppRangeForIterate: + return BuildCppRangeForIterateWitness( + context, loc_id, query_self_const_id, query_specific_interface_id); + // IntFitsIn is for Carbon integer types only. case SemIR::CoreInterface::IntFitsIn: return SemIR::InstId::None; diff --git a/toolchain/check/custom_witness.cpp b/toolchain/check/custom_witness.cpp index 5a35af39e21a..fa97d390542e 100644 --- a/toolchain/check/custom_witness.cpp +++ b/toolchain/check/custom_witness.cpp @@ -704,6 +704,7 @@ auto LookupCustomWitness(Context& context, SemIR::LocId loc_id, case SemIR::CoreInterface::AddAssignWith: case SemIR::CoreInterface::AddWith: case SemIR::CoreInterface::Copy: + case SemIR::CoreInterface::CppRangeForIterate: case SemIR::CoreInterface::CppUnsafeDeref: case SemIR::CoreInterface::Dec: case SemIR::CoreInterface::Default: diff --git a/toolchain/check/testdata/interop/cpp/range_for.carbon b/toolchain/check/testdata/interop/cpp/range_for.carbon new file mode 100644 index 000000000000..1d0acde76be3 --- /dev/null +++ b/toolchain/check/testdata/interop/cpp/range_for.carbon @@ -0,0 +1,358 @@ +// 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-FILE: toolchain/testing/testdata/min_prelude/full.carbon +// +// EXTRA-ARGS: --clang-arg=-std=c++20 +// +// AUTOUPDATE +// TIP: To test this file alone, run: +// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/range_for.carbon +// TIP: To dump output, run: +// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/range_for.carbon + +// --- methods_return_same_type.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline '''c++ +class MutableRange { + struct Iterator { + auto operator*() const -> int&; + auto operator++() -> Iterator&; + friend auto operator==(Iterator, Iterator) -> bool; + friend auto operator!=(Iterator, Iterator) -> bool; + }; +public: + auto begin() -> Iterator; + auto end() -> Iterator; +}; + +class ConstRange { + struct Iterator { + auto operator*() const -> const int&; + auto operator++() -> Iterator&; + friend auto operator==(Iterator, Iterator) -> bool; + friend auto operator!=(Iterator, Iterator) -> bool; + }; +public: + auto begin() const -> Iterator; + auto end() const -> Iterator; +}; +'''; + +// TODO: uncomment after #7181 is merged. +// fn CppRangeForIterate[R:! Core.CppRangeForIterate where .Iterator impls Core.Destroy and .Sentinel impls Core.Destroy](r: R) { +// //@dump-sem-ir-begin +// r.Begin(); +// r.End(); +// //@dump-sem-ir-end +// } + +fn Test(var m: Cpp.MutableRange, var c: Cpp.ConstRange) { + // TODO: replace with Test(m) when #7181 is merged. + m.(Core.CppRangeForIterate.Begin)(); + m.(Core.CppRangeForIterate.End)(); + + // TODO: replace with Test(c) when #7181 is merged. + c.(Core.CppRangeForIterate.Begin)(); + c.(Core.CppRangeForIterate.End)(); +} + +// --- methods_return_different_types.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline '''c++ +class MutableRange { + struct ValueType {}; + + struct Iterator { + auto operator*() const -> ValueType&; + auto operator++() -> Iterator&; + }; + + struct Sentinel { + friend auto operator==(Sentinel, Iterator) -> bool; + friend auto operator!=(Sentinel, Iterator) -> bool; + }; +public: + auto begin() -> Iterator; + auto end() -> Sentinel; +}; + +class ConstRange { + struct ValueType {}; + + struct Iterator { + auto operator*() const -> ValueType; + auto operator++() -> Iterator&; + }; + + struct Sentinel { + friend auto operator==(Sentinel, Iterator) -> bool; + friend auto operator!=(Sentinel, Iterator) -> bool; + }; +public: + auto begin() const -> Iterator; + auto end() const -> Sentinel; +}; +'''; + +// TODO: uncomment after #7181 is merged. +// fn Test[R:! Core.CppRangeForIterate where .Iterator impls Core.Destroy and .Sentinel impls Core.Destroy](r: R) { +// //@dump-sem-ir-begin +// r.Begin(); +// r.End(); +// //@dump-sem-ir-end +// } + +fn TestDriver(var m: Cpp.MutableRange, var c: Cpp.ConstRange) { + // TODO: replace with Test(m) when #7181 is merged. + m.(Core.CppRangeForIterate.Begin)(); + m.(Core.CppRangeForIterate.End)(); + + // TODO: replace with Test(c) when #7181 is merged. + c.(Core.CppRangeForIterate.Begin)(); + c.(Core.CppRangeForIterate.End)(); +} + +// --- fail_todo_adl_return_same_types.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline '''c++ +namespace N { +class MutableRange { + struct Iterator { + auto operator*() const -> int&; + auto operator++() -> Iterator&; + friend auto operator==(Iterator, Iterator) -> bool; + friend auto operator!=(Iterator, Iterator) -> bool; + }; +public: + friend auto begin(MutableRange&) -> Iterator; + friend auto end(MutableRange&) -> Iterator; +}; + +class ConstRange { + struct Iterator { + auto operator*() const -> const int&; + auto operator++() -> Iterator&; + friend auto operator==(Iterator, Iterator) -> bool; + friend auto operator!=(Iterator, Iterator) -> bool; + }; +public: + friend auto begin(const ConstRange&) -> Iterator; + friend auto end(const ConstRange&) -> Iterator; +}; +} // namespace N +'''; + +// TODO: uncomment after #7181 is merged. +// fn CppRangeForIterate[R:! Core.CppRangeForIterate where .Iterator impls Core.Destroy and .Sentinel impls Core.Destroy](r: R) { +// //@dump-sem-ir-begin +// r.Begin(); +// r.End(); +// //@dump-sem-ir-end +// } + +fn Test(var m: Cpp.N.MutableRange, c: Cpp.N.ConstRange) { + // TODO: replace with Test(m) when #7181 is merged. + // CHECK:STDERR: fail_todo_adl_return_same_types.carbon:[[@LINE+4]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: m.(Core.CppRangeForIterate.Begin)(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + m.(Core.CppRangeForIterate.Begin)(); + m.(Core.CppRangeForIterate.End)(); + + // TODO: replace with Test(c) when #7181 is merged. + // CHECK:STDERR: fail_todo_adl_return_same_types.carbon:[[@LINE+4]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: c.(Core.CppRangeForIterate.Begin)(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + c.(Core.CppRangeForIterate.Begin)(); + c.(Core.CppRangeForIterate.End)(); +} + +// --- fail_todo_adl_returns_different_types.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline '''c++ +namespace N { +class MutableRange { + struct ValueType {}; + + struct Iterator { + auto operator*() const -> ValueType&; + auto operator++() -> Iterator&; + }; + + struct Sentinel { + friend auto operator==(Sentinel, Iterator) -> bool; + friend auto operator!=(Sentinel, Iterator) -> bool; + }; +public: + friend auto begin(MutableRange&) -> Iterator; + friend auto end(MutableRange&) -> Sentinel; +}; + +class ConstRange { + struct ValueType {}; + + struct Iterator { + auto operator*() const -> ValueType; + auto operator++() -> Iterator&; + }; + + struct Sentinel { + friend auto operator==(Sentinel, Iterator) -> bool; + friend auto operator!=(Sentinel, Iterator) -> bool; + }; +public: + friend auto begin(const ConstRange&) -> Iterator; + friend auto end(const ConstRange&) -> Sentinel; +}; +} // namespace N +'''; + +// TODO: uncomment after #7181 is merged. +// fn Test[R:! Core.CppRangeForIterate where .Iterator impls Core.Destroy and .Sentinel impls Core.Destroy](r: R) { +// //@dump-sem-ir-begin +// r.Begin(); +// r.End(); +// //@dump-sem-ir-end +// } + +fn TestDriver(var m: Cpp.N.MutableRange, c: Cpp.N.ConstRange) { + // TODO: replace with Test(m) when #7181 is merged. + // CHECK:STDERR: fail_todo_adl_returns_different_types.carbon:[[@LINE+4]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: m.(Core.CppRangeForIterate.Begin)(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + m.(Core.CppRangeForIterate.Begin)(); + m.(Core.CppRangeForIterate.End)(); + + // TODO: replace with Test(c) when #7181 is merged. + // CHECK:STDERR: fail_todo_adl_returns_different_types.carbon:[[@LINE+4]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: c.(Core.CppRangeForIterate.Begin)(); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + c.(Core.CppRangeForIterate.Begin)(); + c.(Core.CppRangeForIterate.End)(); +} + +// --- fail_todo_never_valid.carbon + +// TODO: rename to `fail_never_valid.carbon` after ADL is supported. + +library "[[@TEST_NAME]]"; + +import Cpp inline '''c++ +class NoBeginEnd {}; + +struct NoBeginMethod { + auto end() -> int; +}; + +struct NoEndMethod { + auto begin(); +}; + +struct NoBeginADL { + friend auto end(NoBeginADL) -> int; +}; + +struct NoEndADL { + friend auto begin(NoEndADL) -> int; +}; + +struct BeginMethodEndADL { + auto begin() -> int; + friend auto end(BeginMethodEndADL) -> int; +}; + +struct BeginADLEndMethod { + friend auto begin(BeginADLEndMethod) -> int; + auto end() -> int; +}; +'''; + +fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + +fn TestDriver(no_begin_end: Cpp.NoBeginEnd, + no_begin_method: Cpp.NoBeginMethod, + no_end_method: Cpp.NoEndMethod, + no_begin_adl: Cpp.NoBeginADL, + no_end_adl: Cpp.NoEndADL, + begin_method_end_adl: Cpp.BeginMethodEndADL, + begin_adl_end_method: Cpp.BeginADLEndMethod) +{ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+7]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: Test(no_begin_end); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-13]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(no_begin_end); + + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+7]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: Test(no_begin_method); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-22]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(no_begin_method); + + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+10]]:21: error: function 'begin' with deduced return type cannot be used before it is defined [CppInteropParseError] + // CHECK:STDERR: 74 | Test(no_end_method); + // CHECK:STDERR: | ^ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-53]]:8: note: 'begin' declared here [CppInteropParseNote] + // CHECK:STDERR: 14 | auto begin(); + // CHECK:STDERR: | ^ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-34]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(no_end_method); + + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+7]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: Test(no_begin_adl); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-43]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(no_begin_adl); + + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+7]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: Test(no_end_adl); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-52]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(no_end_adl); + + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+7]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: Test(begin_method_end_adl); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-61]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(begin_method_end_adl); + + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE+7]]:3: error: semantics TODO: `support ADL begin/end` [SemanticsTodo] + // CHECK:STDERR: Test(begin_adl_end_method); + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: fail_todo_never_valid.carbon:[[@LINE-70]]:1: note: while deducing parameters of generic declared here [DeductionGenericHere] + // CHECK:STDERR: fn Test[R:! Core.CppRangeForIterate](unused r: R) {} + // CHECK:STDERR: ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // CHECK:STDERR: + Test(begin_adl_end_method); +} diff --git a/toolchain/sem_ir/core_interface_kind.def b/toolchain/sem_ir/core_interface_kind.def index 2cd1b7525911..64ea86a03717 100644 --- a/toolchain/sem_ir/core_interface_kind.def +++ b/toolchain/sem_ir/core_interface_kind.def @@ -19,6 +19,7 @@ CARBON_SEM_IR_CORE_INTERFACE_KIND(AddAssignWith) CARBON_SEM_IR_CORE_INTERFACE_KIND(AddWith) CARBON_SEM_IR_CORE_INTERFACE_KIND(Copy) +CARBON_SEM_IR_CORE_INTERFACE_KIND(CppRangeForIterate) CARBON_SEM_IR_CORE_INTERFACE_KIND(CppUnsafeDeref) CARBON_SEM_IR_CORE_INTERFACE_KIND(Dec) CARBON_SEM_IR_CORE_INTERFACE_KIND(Default)