mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 16:21:04 +01:00
Support detecting begin()/end() methods for range-for loops (#7185)
This commit adds support for range-based for loops using C++ types. It's currently limited to detecting that `r.begin()` and `r.end()` are available. We should be able to add full support for methods after #7181 is merged. Support for ADL is still a work-in-progress, and will be added at a later time. --------- Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
dd7cfdb149
commit
2aaa061688
@@ -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<SemIR::FunctionDecl>(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<SemIR::FunctionDecl>(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;
|
||||
|
||||
Reference in New Issue
Block a user