mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Take the address of the object when calling an addr self method. (#3349)
Co-authored-by: Jon Ross-Perkins <jperkins@google.com>
This commit is contained in:
co-authored by
Jon Ross-Perkins
parent
3ea3cc38b3
commit
a2e7d5e008
+58
-23
@@ -859,6 +859,62 @@ auto ConvertForExplicitAs(Context& context, Parse::Node as_node,
|
||||
{.kind = ConversionTarget::ExplicitAs, .type_id = type_id});
|
||||
}
|
||||
|
||||
CARBON_DIAGNOSTIC(InCallToFunction, Note, "Calling function declared here.");
|
||||
|
||||
// Convert the object argument in a method call to match the `self` parameter.
|
||||
static auto ConvertSelf(Context& context, Parse::Node call_parse_node,
|
||||
Parse::Node callee_parse_node,
|
||||
SemIR::SelfParameter self_param, SemIR::NodeId self_id)
|
||||
-> SemIR::NodeId {
|
||||
if (!self_id.is_valid()) {
|
||||
CARBON_DIAGNOSTIC(MissingObjectInMethodCall, Error,
|
||||
"Missing object argument in method call.");
|
||||
context.emitter()
|
||||
.Build(call_parse_node, MissingObjectInMethodCall)
|
||||
.Note(callee_parse_node, InCallToFunction)
|
||||
.Emit();
|
||||
return SemIR::NodeId::BuiltinError;
|
||||
}
|
||||
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
InCallToFunctionSelf, Note,
|
||||
"Initializing `{0}` parameter of method declared here.",
|
||||
llvm::StringLiteral);
|
||||
builder.Note(self_param.parse_node, InCallToFunctionSelf,
|
||||
self_param.is_addr_self.index
|
||||
? llvm::StringLiteral("addr self")
|
||||
: llvm::StringLiteral("self"));
|
||||
});
|
||||
|
||||
// For `addr self`, take the address of the object argument.
|
||||
auto self_or_addr_id = self_id;
|
||||
if (self_param.is_addr_self.index) {
|
||||
self_or_addr_id =
|
||||
ConvertToValueOrReferenceExpression(context, self_or_addr_id);
|
||||
auto self = context.nodes().Get(self_or_addr_id);
|
||||
switch (SemIR::GetExpressionCategory(context.sem_ir(), self_id)) {
|
||||
case SemIR::ExpressionCategory::Error:
|
||||
case SemIR::ExpressionCategory::DurableReference:
|
||||
case SemIR::ExpressionCategory::EphemeralReference:
|
||||
break;
|
||||
default:
|
||||
CARBON_DIAGNOSTIC(AddrSelfIsNonReference, Error,
|
||||
"`addr self` method cannot be invoked on a value.");
|
||||
context.emitter().Emit(call_parse_node, AddrSelfIsNonReference);
|
||||
return SemIR::NodeId::BuiltinError;
|
||||
}
|
||||
self_or_addr_id = context.AddNode(SemIR::AddressOf{
|
||||
self.parse_node(),
|
||||
context.GetPointerType(self.parse_node(), self.type_id()),
|
||||
self_or_addr_id});
|
||||
}
|
||||
|
||||
return ConvertToValueOfType(context, call_parse_node, self_or_addr_id,
|
||||
self_param.type_id);
|
||||
}
|
||||
|
||||
auto ConvertCallArgs(Context& context, Parse::Node call_parse_node,
|
||||
SemIR::NodeId self_id,
|
||||
llvm::ArrayRef<SemIR::NodeId> arg_refs,
|
||||
@@ -870,8 +926,6 @@ auto ConvertCallArgs(Context& context, Parse::Node call_parse_node,
|
||||
context.sem_ir().node_blocks().Get(implicit_param_refs_id);
|
||||
auto param_refs = context.sem_ir().node_blocks().Get(param_refs_id);
|
||||
|
||||
CARBON_DIAGNOSTIC(InCallToFunction, Note, "Calling function declared here.");
|
||||
|
||||
// If sizes mismatch, fail early.
|
||||
if (arg_refs.size() != param_refs.size()) {
|
||||
CARBON_DIAGNOSTIC(CallArgCountMismatch, Error,
|
||||
@@ -895,27 +949,8 @@ auto ConvertCallArgs(Context& context, Parse::Node call_parse_node,
|
||||
for (auto implicit_param_id : implicit_param_refs) {
|
||||
auto param = context.nodes().Get(implicit_param_id);
|
||||
if (auto self_param = param.TryAs<SemIR::SelfParameter>()) {
|
||||
if (!self_id.is_valid()) {
|
||||
CARBON_DIAGNOSTIC(MissingObjectInMethodCall, Error,
|
||||
"Missing object argument in method call.");
|
||||
context.emitter()
|
||||
.Build(call_parse_node, MissingObjectInMethodCall)
|
||||
.Note(callee_parse_node, InCallToFunction)
|
||||
.Emit();
|
||||
return SemIR::NodeBlockId::Invalid;
|
||||
}
|
||||
|
||||
DiagnosticAnnotationScope annotate_diagnostics(
|
||||
&context.emitter(), [&](auto& builder) {
|
||||
CARBON_DIAGNOSTIC(
|
||||
InCallToFunctionSelf, Note,
|
||||
"Initializing self parameter of method declared here.");
|
||||
builder.Note(self_param->parse_node, InCallToFunctionSelf);
|
||||
});
|
||||
|
||||
// TODO: Handle `addr self`.
|
||||
auto converted_self_id = ConvertToValueOfType(
|
||||
context, call_parse_node, self_id, self_param->type_id);
|
||||
auto converted_self_id = ConvertSelf(
|
||||
context, call_parse_node, callee_parse_node, *self_param, self_id);
|
||||
if (converted_self_id == SemIR::NodeId::BuiltinError) {
|
||||
return SemIR::NodeBlockId::Invalid;
|
||||
}
|
||||
|
||||
+37
-12
@@ -9,18 +9,33 @@ class Class {
|
||||
fn G[addr self: Class]();
|
||||
}
|
||||
|
||||
fn F(c: Class) {
|
||||
// TODO: This is the wrong reason to reject this. We should complain that `c` is not an lvalue.
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE+6]]:6: ERROR: Cannot implicitly convert from `Class` to `Class*`.
|
||||
fn F(c: Class, p: Class*) {
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE+6]]:6: ERROR: `addr self` method cannot be invoked on a value.
|
||||
// CHECK:STDERR: c.F();
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE-9]]:13: Initializing self parameter of method declared here.
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE-8]]:13: Initializing `addr self` parameter of method declared here.
|
||||
// CHECK:STDERR: fn F[addr self: Class*]();
|
||||
// CHECK:STDERR: ^
|
||||
c.F();
|
||||
|
||||
// TODO: This is invalid and should be rejected.
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE+6]]:6: ERROR: `addr self` method cannot be invoked on a value.
|
||||
// CHECK:STDERR: c.G();
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE-15]]:13: Initializing `addr self` parameter of method declared here.
|
||||
// CHECK:STDERR: fn G[addr self: Class]();
|
||||
// CHECK:STDERR: ^
|
||||
c.G();
|
||||
|
||||
// This call is OK.
|
||||
(*p).F();
|
||||
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE+6]]:9: ERROR: Cannot implicitly convert from `Class*` to `Class`.
|
||||
// CHECK:STDERR: (*p).G();
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_addr_self.carbon:[[@LINE-26]]:13: Initializing `addr self` parameter of method declared here.
|
||||
// CHECK:STDERR: fn G[addr self: Class]();
|
||||
// CHECK:STDERR: ^
|
||||
(*p).G();
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: file "fail_addr_self.carbon" {
|
||||
@@ -43,15 +58,25 @@ fn F(c: Class) {
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @G[%self.addr: Class]();
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @F.2(%c: Class) {
|
||||
// CHECK:STDOUT: fn @F.2(%c: Class, %p: Class*) {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %.loc10: type = tuple_type ()
|
||||
// CHECK:STDOUT: %.loc7: type = ptr_type {}
|
||||
// CHECK:STDOUT: %c.ref.loc20: Class = name_reference "c", %c
|
||||
// CHECK:STDOUT: %.loc20_4: <bound method> = bound_method %c.ref.loc20, @Class.%F
|
||||
// CHECK:STDOUT: %.loc20_6: init () = call %.loc20_4(<invalid>)
|
||||
// CHECK:STDOUT: %c.ref.loc23: Class = name_reference "c", %c
|
||||
// CHECK:STDOUT: %.loc23_4: <bound method> = bound_method %c.ref.loc23, @Class.%G
|
||||
// CHECK:STDOUT: %.loc23_6: init () = call %.loc23_4(%c.ref.loc23)
|
||||
// CHECK:STDOUT: %c.ref.loc19: Class = name_reference "c", %c
|
||||
// CHECK:STDOUT: %.loc19_4: <bound method> = bound_method %c.ref.loc19, @Class.%F
|
||||
// CHECK:STDOUT: %.loc19_6: init () = call %.loc19_4(<invalid>)
|
||||
// CHECK:STDOUT: %c.ref.loc27: Class = name_reference "c", %c
|
||||
// CHECK:STDOUT: %.loc27_4: <bound method> = bound_method %c.ref.loc27, @Class.%G
|
||||
// CHECK:STDOUT: %.loc27_6: init () = call %.loc27_4(<invalid>)
|
||||
// CHECK:STDOUT: %p.ref.loc30: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc30_4.1: ref Class = dereference %p.ref.loc30
|
||||
// CHECK:STDOUT: %.loc30_7: <bound method> = bound_method %.loc30_4.1, @Class.%F
|
||||
// CHECK:STDOUT: %.loc30_4.2: Class* = address_of %.loc30_4.1
|
||||
// CHECK:STDOUT: %.loc30_9: init () = call %.loc30_7(%.loc30_4.2)
|
||||
// CHECK:STDOUT: %p.ref.loc38: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc38_4.1: ref Class = dereference %p.ref.loc38
|
||||
// CHECK:STDOUT: %.loc38_7: <bound method> = bound_method %.loc38_4.1, @Class.%G
|
||||
// CHECK:STDOUT: %.loc38_4.2: Class* = address_of %.loc38_4.1
|
||||
// CHECK:STDOUT: %.loc38_9: init () = call %.loc38_7(<invalid>)
|
||||
// CHECK:STDOUT: return
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ fn CallWrongSelf(ws: WrongSelf) {
|
||||
// CHECK:STDERR: fail_self.carbon:[[@LINE+6]]:7: ERROR: Cannot implicitly convert from `WrongSelf` to `Class`.
|
||||
// CHECK:STDERR: ws.F();
|
||||
// CHECK:STDERR: ^
|
||||
// CHECK:STDERR: fail_self.carbon:[[@LINE-7]]:8: Initializing self parameter of method declared here.
|
||||
// CHECK:STDERR: fail_self.carbon:[[@LINE-7]]:8: Initializing `self` parameter of method declared here.
|
||||
// CHECK:STDERR: fn F[self: Class]();
|
||||
// CHECK:STDERR: ^
|
||||
ws.F();
|
||||
|
||||
+120
-13
@@ -6,6 +6,7 @@
|
||||
|
||||
class Class {
|
||||
fn F[self: Class]() -> i32;
|
||||
fn G[addr self: Class*]() -> i32;
|
||||
|
||||
var k: i32;
|
||||
}
|
||||
@@ -20,22 +21,53 @@ fn Call(c: Class) -> i32 {
|
||||
return c.F();
|
||||
}
|
||||
|
||||
fn CallWithAddr() -> i32 {
|
||||
var c: Class;
|
||||
return c.G();
|
||||
}
|
||||
|
||||
fn CallFThroughPointer(p: Class*) -> i32 {
|
||||
return (*p).F();
|
||||
}
|
||||
|
||||
fn CallGThroughPointer(p: Class*) -> i32 {
|
||||
return (*p).G();
|
||||
}
|
||||
|
||||
fn Make() -> Class;
|
||||
|
||||
fn CallFOnInitializingExpression() -> i32 {
|
||||
return Make().F();
|
||||
}
|
||||
|
||||
fn CallGOnInitializingExpression() -> i32 {
|
||||
return Make().G();
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: file "method.carbon" {
|
||||
// CHECK:STDOUT: class_declaration @Class, ()
|
||||
// CHECK:STDOUT: %Class: type = class_type @Class
|
||||
// CHECK:STDOUT: %.loc11: type = struct_type {.k: i32}
|
||||
// CHECK:STDOUT: %.loc12: type = struct_type {.k: i32}
|
||||
// CHECK:STDOUT: %F: <function> = fn_decl @F
|
||||
// CHECK:STDOUT: %Call: <function> = fn_decl @Call
|
||||
// CHECK:STDOUT: %CallWithAddr: <function> = fn_decl @CallWithAddr
|
||||
// CHECK:STDOUT: %CallFThroughPointer: <function> = fn_decl @CallFThroughPointer
|
||||
// CHECK:STDOUT: %CallGThroughPointer: <function> = fn_decl @CallGThroughPointer
|
||||
// CHECK:STDOUT: %Make: <function> = fn_decl @Make
|
||||
// CHECK:STDOUT: %CallFOnInitializingExpression: <function> = fn_decl @CallFOnInitializingExpression
|
||||
// CHECK:STDOUT: %CallGOnInitializingExpression: <function> = fn_decl @CallGOnInitializingExpression
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: class @Class {
|
||||
// CHECK:STDOUT: %F: <function> = fn_decl @F
|
||||
// CHECK:STDOUT: %.loc10_8.1: type = unbound_field_type Class, i32
|
||||
// CHECK:STDOUT: %.loc10_8.2: <unbound field of class Class> = field "k", member0
|
||||
// CHECK:STDOUT: %k: <unbound field of class Class> = bind_name "k", %.loc10_8.2
|
||||
// CHECK:STDOUT: %G: <function> = fn_decl @G
|
||||
// CHECK:STDOUT: %.loc11_8.1: type = unbound_field_type Class, i32
|
||||
// CHECK:STDOUT: %.loc11_8.2: <unbound field of class Class> = field "k", member0
|
||||
// CHECK:STDOUT: %k: <unbound field of class Class> = bind_name "k", %.loc11_8.2
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: !members:
|
||||
// CHECK:STDOUT: .F = %F
|
||||
// CHECK:STDOUT: .G = %G
|
||||
// CHECK:STDOUT: .k = %k
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
@@ -43,18 +75,93 @@ fn Call(c: Class) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %.loc7: type = ptr_type {.k: i32}
|
||||
// CHECK:STDOUT: %self.ref: Class = name_reference "self", %self
|
||||
// CHECK:STDOUT: %.loc14_14.1: ref i32 = class_field_access %self.ref, member0
|
||||
// CHECK:STDOUT: %.loc14_14.2: i32 = bind_value %.loc14_14.1
|
||||
// CHECK:STDOUT: return %.loc14_14.2
|
||||
// CHECK:STDOUT: %.loc15_14.1: ref i32 = class_field_access %self.ref, member0
|
||||
// CHECK:STDOUT: %.loc15_14.2: i32 = bind_value %.loc15_14.1
|
||||
// CHECK:STDOUT: return %.loc15_14.2
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @G[%self.addr: Class*]() -> i32;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Call(%c: Class) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %c.ref: Class = name_reference "c", %c
|
||||
// CHECK:STDOUT: %.loc20_11: <bound method> = bound_method %c.ref, @Class.%F
|
||||
// CHECK:STDOUT: %.loc20_13.1: init i32 = call %.loc20_11(%c.ref)
|
||||
// CHECK:STDOUT: %.loc20_13.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc20_13.3: ref i32 = temporary %.loc20_13.2, %.loc20_13.1
|
||||
// CHECK:STDOUT: %.loc20_13.4: i32 = bind_value %.loc20_13.3
|
||||
// CHECK:STDOUT: return %.loc20_13.4
|
||||
// CHECK:STDOUT: %.loc21_11: <bound method> = bound_method %c.ref, @Class.%F
|
||||
// CHECK:STDOUT: %.loc21_13.1: init i32 = call %.loc21_11(%c.ref)
|
||||
// CHECK:STDOUT: %.loc21_13.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc21_13.3: ref i32 = temporary %.loc21_13.2, %.loc21_13.1
|
||||
// CHECK:STDOUT: %.loc21_13.4: i32 = bind_value %.loc21_13.3
|
||||
// CHECK:STDOUT: return %.loc21_13.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallWithAddr() -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Class.ref: type = name_reference "Class", file.%Class
|
||||
// CHECK:STDOUT: %c.var: ref Class = var "c"
|
||||
// CHECK:STDOUT: %c: ref Class = bind_name "c", %c.var
|
||||
// CHECK:STDOUT: %c.ref: ref Class = name_reference "c", %c
|
||||
// CHECK:STDOUT: %.loc26_11: <bound method> = bound_method %c.ref, @Class.%G
|
||||
// CHECK:STDOUT: %.loc26_10: Class* = address_of %c.ref
|
||||
// CHECK:STDOUT: %.loc26_13.1: init i32 = call %.loc26_11(%.loc26_10)
|
||||
// CHECK:STDOUT: %.loc26_13.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc26_13.3: ref i32 = temporary %.loc26_13.2, %.loc26_13.1
|
||||
// CHECK:STDOUT: %.loc26_13.4: i32 = bind_value %.loc26_13.3
|
||||
// CHECK:STDOUT: return %.loc26_13.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallFThroughPointer(%p: Class*) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc30_11.1: ref Class = dereference %p.ref
|
||||
// CHECK:STDOUT: %.loc30_14: <bound method> = bound_method %.loc30_11.1, @Class.%F
|
||||
// CHECK:STDOUT: %.loc30_11.2: Class = bind_value %.loc30_11.1
|
||||
// CHECK:STDOUT: %.loc30_16.1: init i32 = call %.loc30_14(%.loc30_11.2)
|
||||
// CHECK:STDOUT: %.loc30_16.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc30_16.3: ref i32 = temporary %.loc30_16.2, %.loc30_16.1
|
||||
// CHECK:STDOUT: %.loc30_16.4: i32 = bind_value %.loc30_16.3
|
||||
// CHECK:STDOUT: return %.loc30_16.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallGThroughPointer(%p: Class*) -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %p.ref: Class* = name_reference "p", %p
|
||||
// CHECK:STDOUT: %.loc34_11.1: ref Class = dereference %p.ref
|
||||
// CHECK:STDOUT: %.loc34_14: <bound method> = bound_method %.loc34_11.1, @Class.%G
|
||||
// CHECK:STDOUT: %.loc34_11.2: Class* = address_of %.loc34_11.1
|
||||
// CHECK:STDOUT: %.loc34_16.1: init i32 = call %.loc34_14(%.loc34_11.2)
|
||||
// CHECK:STDOUT: %.loc34_16.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc34_16.3: ref i32 = temporary %.loc34_16.2, %.loc34_16.1
|
||||
// CHECK:STDOUT: %.loc34_16.4: i32 = bind_value %.loc34_16.3
|
||||
// CHECK:STDOUT: return %.loc34_16.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @Make() -> %return: Class;
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallFOnInitializingExpression() -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Make.ref: <function> = name_reference "Make", file.%Make
|
||||
// CHECK:STDOUT: %.loc40_14.1: ref Class = temporary_storage
|
||||
// CHECK:STDOUT: %.loc40_14.2: init Class = call %Make.ref() to %.loc40_14.1
|
||||
// CHECK:STDOUT: %.loc40_14.3: ref Class = temporary %.loc40_14.1, %.loc40_14.2
|
||||
// CHECK:STDOUT: %.loc40_16: <bound method> = bound_method %.loc40_14.3, @Class.%F
|
||||
// CHECK:STDOUT: %.loc40_14.4: Class = bind_value %.loc40_14.3
|
||||
// CHECK:STDOUT: %.loc40_18.1: init i32 = call %.loc40_16(%.loc40_14.4)
|
||||
// CHECK:STDOUT: %.loc40_18.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc40_18.3: ref i32 = temporary %.loc40_18.2, %.loc40_18.1
|
||||
// CHECK:STDOUT: %.loc40_18.4: i32 = bind_value %.loc40_18.3
|
||||
// CHECK:STDOUT: return %.loc40_18.4
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: fn @CallGOnInitializingExpression() -> i32 {
|
||||
// CHECK:STDOUT: !entry:
|
||||
// CHECK:STDOUT: %Make.ref: <function> = name_reference "Make", file.%Make
|
||||
// CHECK:STDOUT: %.loc44_14.1: ref Class = temporary_storage
|
||||
// CHECK:STDOUT: %.loc44_14.2: init Class = call %Make.ref() to %.loc44_14.1
|
||||
// CHECK:STDOUT: %.loc44_14.3: ref Class = temporary %.loc44_14.1, %.loc44_14.2
|
||||
// CHECK:STDOUT: %.loc44_16: <bound method> = bound_method %.loc44_14.3, @Class.%G
|
||||
// CHECK:STDOUT: %.loc44_14.4: Class* = address_of %.loc44_14.3
|
||||
// CHECK:STDOUT: %.loc44_18.1: init i32 = call %.loc44_16(%.loc44_14.4)
|
||||
// CHECK:STDOUT: %.loc44_18.2: ref i32 = temporary_storage
|
||||
// CHECK:STDOUT: %.loc44_18.3: ref i32 = temporary %.loc44_18.2, %.loc44_18.1
|
||||
// CHECK:STDOUT: %.loc44_18.4: i32 = bind_value %.loc44_18.3
|
||||
// CHECK:STDOUT: return %.loc44_18.4
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
@@ -110,6 +110,7 @@ CARBON_DIAGNOSTIC_KIND(ParametersRequiredByIntroducer)
|
||||
CARBON_DIAGNOSTIC_KIND(SemanticsTodo)
|
||||
|
||||
// Function call checking.
|
||||
CARBON_DIAGNOSTIC_KIND(AddrSelfIsNonReference)
|
||||
CARBON_DIAGNOSTIC_KIND(CallArgCountMismatch)
|
||||
CARBON_DIAGNOSTIC_KIND(CallToNonCallable)
|
||||
CARBON_DIAGNOSTIC_KIND(InCallToFunction)
|
||||
|
||||
+2
-2
@@ -13,8 +13,7 @@ class C {
|
||||
|
||||
fn F(p: C*) {
|
||||
let n: i32 = (*p).Get();
|
||||
// TODO: Support `addr self`.
|
||||
// (*p).Set(n);
|
||||
(*p).Set(n);
|
||||
}
|
||||
|
||||
// CHECK:STDOUT: ; ModuleID = 'method.carbon'
|
||||
@@ -29,5 +28,6 @@ fn F(p: C*) {
|
||||
// CHECK:STDOUT: %temp = alloca i32, align 4
|
||||
// CHECK:STDOUT: store i32 %Get, ptr %temp, align 4
|
||||
// CHECK:STDOUT: %1 = load i32, ptr %temp, align 4
|
||||
// CHECK:STDOUT: call void @Set(ptr %p, i32 %1)
|
||||
// CHECK:STDOUT: ret void
|
||||
// CHECK:STDOUT: }
|
||||
|
||||
Reference in New Issue
Block a user