mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix bugs relating to optional interface addr-of #2244.
This commit is contained in:
@@ -66,6 +66,7 @@
|
||||
- Assert casting bitstruct to short/char #2237.
|
||||
- @tag didn't work with members #2236.
|
||||
- Assert comparing untyped lists #2240.
|
||||
- Fix bugs relating to optional interface addr-of #2244.
|
||||
|
||||
### Stdlib changes
|
||||
- Deprecate `String.is_zstr` and `String.quick_zstr` #2188.
|
||||
|
||||
@@ -282,11 +282,8 @@ struct Type_
|
||||
TypeKind type_kind;
|
||||
CanonicalType *canonical;
|
||||
const char *name;
|
||||
union
|
||||
{
|
||||
Type **type_cache;
|
||||
Type *func_ptr;
|
||||
};
|
||||
Type **type_cache;
|
||||
Type *func_ptr;
|
||||
union
|
||||
{
|
||||
void *backend_type;
|
||||
|
||||
@@ -2372,8 +2372,8 @@ static inline void llvm_emit_post_inc_dec(GenContext *c, BEValue *value, Expr *e
|
||||
static void llvm_emit_dynamic_method_addr(GenContext *c, BEValue *value, Expr *expr)
|
||||
{
|
||||
llvm_emit_expr(c, value, expr->access_resolved_expr.parent);
|
||||
llvm_emit_type_from_any(c, value);
|
||||
llvm_value_rvalue(c, value);
|
||||
llvm_emit_type_from_any(c, value);
|
||||
LLVMValueRef introspect = LLVMBuildIntToPtr(c->builder, value->value, c->ptr_type, "");
|
||||
|
||||
Decl *dyn_fn = expr->access_resolved_expr.ref;
|
||||
|
||||
@@ -8108,10 +8108,11 @@ RESOLVED:
|
||||
RETURN_SEMA_ERROR(inner, error);
|
||||
}
|
||||
|
||||
Type *no_optional = type_no_optional(inner->type)->canonical;
|
||||
// 3. Get the pointer of the underlying type.
|
||||
if (inner->type->type_kind == TYPE_FUNC_RAW)
|
||||
if (no_optional->type_kind == TYPE_FUNC_RAW)
|
||||
{
|
||||
expr->type = type_get_func_ptr(inner->type);
|
||||
expr->type = type_add_optional(type_get_func_ptr(no_optional), IS_OPTIONAL((inner)));
|
||||
return true;
|
||||
}
|
||||
expr->type = type_get_ptr_recurse(inner->type);
|
||||
|
||||
33
test/test_suite/any/interface_optional.c3
Normal file
33
test/test_suite/any/interface_optional.c3
Normal file
@@ -0,0 +1,33 @@
|
||||
module repro;
|
||||
|
||||
import std::io;
|
||||
|
||||
interface VeryOptional
|
||||
{
|
||||
fn void do_something() @optional;
|
||||
}
|
||||
|
||||
struct Foo (VeryOptional)
|
||||
{
|
||||
String name;
|
||||
}
|
||||
|
||||
Foo foo = { "Foo" };
|
||||
|
||||
fn VeryOptional? get_very_optional()
|
||||
{
|
||||
return &foo;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
VeryOptional? v = get_very_optional();
|
||||
if (&v.do_something) // #error: expression may not be an optional
|
||||
{
|
||||
v.do_something();
|
||||
}
|
||||
else
|
||||
{
|
||||
io::printfn("do_something is not implemented for Foo");
|
||||
}
|
||||
}
|
||||
106
test/test_suite/any/interface_optional_try.c3t
Normal file
106
test/test_suite/any/interface_optional_try.c3t
Normal file
@@ -0,0 +1,106 @@
|
||||
// #target: macos-x64
|
||||
module test;
|
||||
import std::io;
|
||||
|
||||
interface VeryOptional
|
||||
{
|
||||
fn void do_something() @optional;
|
||||
}
|
||||
|
||||
struct Foo (VeryOptional)
|
||||
{
|
||||
String name;
|
||||
}
|
||||
|
||||
Foo foo = { "Foo" };
|
||||
|
||||
fn VeryOptional? get_very_optional()
|
||||
{
|
||||
return &foo;
|
||||
}
|
||||
|
||||
fn void main()
|
||||
{
|
||||
VeryOptional? v = get_very_optional();
|
||||
if (try x = &v.do_something)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
io::printfn("do_something is not implemented for Foo");
|
||||
}
|
||||
}
|
||||
|
||||
/* #expect: test.ll
|
||||
|
||||
define void @test.main() #0 {
|
||||
entry:
|
||||
%v = alloca %any, align 8
|
||||
%v.f = alloca i64, align 8
|
||||
%retparam = alloca %any, align 8
|
||||
%x = alloca ptr, align 8
|
||||
%.inlinecache = alloca ptr, align 8
|
||||
%.cachedtype = alloca ptr, align 8
|
||||
%retparam3 = alloca i64, align 8
|
||||
store ptr null, ptr %.cachedtype, align 8
|
||||
%0 = call i64 @test.get_very_optional(ptr %retparam)
|
||||
%not_err = icmp eq i64 %0, 0
|
||||
%1 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
|
||||
br i1 %1, label %after_check, label %assign_optional
|
||||
|
||||
assign_optional: ; preds = %entry
|
||||
store i64 %0, ptr %v.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_check: ; preds = %entry
|
||||
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %v, ptr align 8 %retparam, i32 16, i1 false)
|
||||
store i64 0, ptr %v.f, align 8
|
||||
br label %after_assign
|
||||
|
||||
after_assign: ; preds = %after_check, %assign_optional
|
||||
store ptr null, ptr %x, align 8
|
||||
%optval = load i64, ptr %v.f, align 8
|
||||
%not_err1 = icmp eq i64 %optval, 0
|
||||
%2 = call i1 @llvm.expect.i1(i1 %not_err1, i1 true)
|
||||
br i1 %2, label %after_check2, label %catch_landing
|
||||
|
||||
after_check2: ; preds = %after_assign
|
||||
%3 = load %any, ptr %v, align 8
|
||||
%4 = extractvalue %any %3, 1
|
||||
%5 = inttoptr i64 %4 to ptr
|
||||
%type = load ptr, ptr %.cachedtype, align 8
|
||||
%6 = icmp eq ptr %5, %type
|
||||
br i1 %6, label %cache_hit, label %cache_miss
|
||||
|
||||
cache_miss: ; preds = %after_check2
|
||||
%ptradd = getelementptr inbounds i8, ptr %5, i64 16
|
||||
%7 = load ptr, ptr %ptradd, align 8
|
||||
%8 = call ptr @.dyn_search(ptr %7, ptr @"$sel.do_something")
|
||||
store ptr %8, ptr %.inlinecache, align 8
|
||||
store ptr %5, ptr %.cachedtype, align 8
|
||||
br label %9
|
||||
|
||||
cache_hit: ; preds = %after_check2
|
||||
%cache_hit_fn = load ptr, ptr %.inlinecache, align 8
|
||||
br label %9
|
||||
|
||||
9: ; preds = %cache_hit, %cache_miss
|
||||
%fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %8, %cache_miss ]
|
||||
store ptr %fn_phi, ptr %x, align 8
|
||||
br label %phi_try_catch
|
||||
|
||||
catch_landing: ; preds = %after_assign
|
||||
br label %phi_try_catch
|
||||
|
||||
phi_try_catch: ; preds = %catch_landing, %9
|
||||
%val = phi i1 [ true, %9 ], [ false, %catch_landing ]
|
||||
br i1 %val, label %if.exit, label %if.else
|
||||
|
||||
if.else: ; preds = %phi_try_catch
|
||||
%10 = call i64 @std.io.printfn(ptr %retparam3, ptr @.str.1, i64 39, ptr null, i64 0)
|
||||
br label %if.exit
|
||||
|
||||
if.exit: ; preds = %if.else, %phi_try_catch
|
||||
ret void
|
||||
}
|
||||
Reference in New Issue
Block a user