From d91c289bf611fbcf5ae253b7a7c5c19fa402416b Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 3 Aug 2024 03:08:38 +0200 Subject: [PATCH] Distinct inline can now be called if it is aliasing a function pointer. --- releasenotes.md | 1 + src/compiler/llvm_codegen_expr.c | 3 ++- src/compiler/sema_expr.c | 3 ++- .../test_suite/distinct/distinct_function.c3t | 23 +++++++++++++++++-- .../distinct/distinct_function_call.c3 | 16 +++++++++++++ 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 test/test_suite/distinct/distinct_function_call.c3 diff --git a/releasenotes.md b/releasenotes.md index d3576265e..90e17b138 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -37,6 +37,7 @@ - Assertion with duplicate function pointer signatures #1286 - Distinct func type would not accept direct function address assign. #1287 - Distinct inline would not implement protocol if the inlined implemented it. #1292 +- Distinct inline can now be called if it is aliasing a function pointer. ### Stdlib changes diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index ee1725c67..257caac5b 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6017,7 +6017,8 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr Expr *function = exprptr(expr->call_expr.function); // 1a. Find the pointee type for the function pointer: - Type *type = function->type->canonical->pointer; + assert(type_flatten(function->type)->type_kind == TYPE_FUNC_PTR); + Type *type = type_flatten(function->type)->pointer; // 1b. Find the type signature using the underlying pointer. prototype = type_get_resolved_prototype(type); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 549b2819a..372debbca 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1844,6 +1844,7 @@ static inline bool sema_call_analyse_func_invocation(SemaContext *context, Decl static inline bool sema_expr_analyse_var_call(SemaContext *context, Expr *expr, Type *func_ptr_type, bool optional, bool *no_match_ref) { Decl *decl = NULL; + func_ptr_type = type_flat_distinct_inline(func_ptr_type); if (func_ptr_type->type_kind != TYPE_FUNC_PTR) { if (no_match_ref) @@ -1851,7 +1852,7 @@ static inline bool sema_expr_analyse_var_call(SemaContext *context, Expr *expr, *no_match_ref = true; return false; } - RETURN_SEMA_ERROR(expr, "Only macros, functions and function pointers maybe invoked, this is of type '%s'.", + RETURN_SEMA_ERROR(expr, "Only macros, functions and function pointers may be invoked, this is of type '%s'.", type_to_error_string(func_ptr_type)); } Type *pointee = func_ptr_type->pointer; diff --git a/test/test_suite/distinct/distinct_function.c3t b/test/test_suite/distinct/distinct_function.c3t index fe2966e92..f5669fc27 100644 --- a/test/test_suite/distinct/distinct_function.c3t +++ b/test/test_suite/distinct/distinct_function.c3t @@ -1,7 +1,8 @@ -module output; +module test; def FnA = fn void(int*); distinct FnB = FnA; +distinct FnC = inline FnA; fn void func(int*) {} @@ -11,4 +12,22 @@ fn void main() FnB b = (FnB)&func; FnB b2 = &func; FnB b3 = fn (int* x) {}; -} \ No newline at end of file + FnC c = &func; + c(null); +} + +/* #expect: test.ll + + %a = alloca ptr, align 8 + %b = alloca ptr, align 8 + %b2 = alloca ptr, align 8 + %b3 = alloca ptr, align 8 + %c = alloca ptr, align 8 + store ptr @test.func, ptr %a, align 8 + store ptr @test.func, ptr %b, align 8 + store ptr @test.func, ptr %b2, align 8 + store ptr @"test.main$lambda1", ptr %b3, align 8 + store ptr @test.func, ptr %c, align 8 + %0 = load ptr, ptr %c, align 8 + call void %0(ptr null) + ret void diff --git a/test/test_suite/distinct/distinct_function_call.c3 b/test/test_suite/distinct/distinct_function_call.c3 new file mode 100644 index 000000000..23e5eabc3 --- /dev/null +++ b/test/test_suite/distinct/distinct_function_call.c3 @@ -0,0 +1,16 @@ +def Abc = fn void(); +distinct Foo = inline Abc; +struct Bar +{ + inline Abc a; +} +fn void test() +{ +} +fn void main() +{ + Foo f = &test; + Bar b = { &test }; + f(); + b(); // #error: may be invoked +} \ No newline at end of file