mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 19:20:13 +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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user