Usage of @noreturn macro is type-checked as if it returns #1913.

This commit is contained in:
Christoffer Lerno
2025-01-31 16:19:12 +01:00
parent 9092defd46
commit 50c1aac9bb
11 changed files with 94 additions and 67 deletions

View File

@@ -36,7 +36,8 @@
- Missing error when placing a single statement for-body on a new row #1892.
- Fix bug where in dead code, only the first statement would be turned into a nop.
- Remove unused $inline argument to mem::copy.
- defer is broken when placed before a $foreach #1912.
- Defer is broken when placed before a $foreach #1912.
- Usage of @noreturn macro is type-checked as if it returns #1913.
### Stdlib changes
- Added '%h' and '%H' for printing out binary data in hexadecimal using the formatter.

View File

@@ -5124,7 +5124,7 @@ void llvm_add_abi_call_attributes(GenContext *c, LLVMValueRef call_value, int co
}
void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype *prototype, LLVMTypeRef func_type, LLVMValueRef func, LLVMValueRef *args, unsigned arg_count, int inline_flag, LLVMValueRef error_var, bool sret_return, BEValue *synthetic_return_param)
void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype *prototype, LLVMTypeRef func_type, LLVMValueRef func, LLVMValueRef *args, unsigned arg_count, int inline_flag, LLVMValueRef error_var, bool sret_return, BEValue *synthetic_return_param, bool no_return)
{
ABIArgInfo *ret_info = prototype->ret_abi_info;
Type *call_return_type = prototype->abi_ret_type;
@@ -5134,6 +5134,10 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype
{
LLVMSetInstructionCallConv(call_value, llvm_call_convention_from_call(prototype->call_abi));
}
if (no_return)
{
llvm_attribute_add_call(c, call_value, attribute_id.noreturn, -1, 0);
}
switch (inline_flag)
{
case -1:
@@ -5145,7 +5149,6 @@ void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype
default:
break;
}
ASSERT(!prototype->ret_by_ref || prototype->ret_by_ref_abi_info->kind != ABI_ARG_INDIRECT);
llvm_add_abi_call_attributes(c, call_value, vec_size(prototype->param_types), prototype->abi_args);
@@ -5442,6 +5445,7 @@ INLINE void llvm_emit_call_invocation(GenContext *c, BEValue *result_value,
Expr **args,
BEValue *values,
int inline_flag,
bool no_return,
LLVMValueRef func,
LLVMTypeRef func_type,
Expr **varargs)
@@ -5583,7 +5587,7 @@ INLINE void llvm_emit_call_invocation(GenContext *c, BEValue *result_value,
// 10. Create the actual call (remember to emit a loc, because we might have shifted loc emitting the params)
EMIT_SPAN(c, span);
llvm_emit_raw_call(c, result_value, prototype, func_type, func, arg_values, arg_count, inline_flag, error_var, sret_return, &synthetic_return_param);
llvm_emit_raw_call(c, result_value, prototype, func_type, func, arg_values, arg_count, inline_flag, error_var, sret_return, &synthetic_return_param, no_return);
// 17i. The simple case here is where there is a normal return.
// In this case be_value already holds the result
@@ -5711,6 +5715,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
func_type = llvm_get_type(c, function_decl->type);
}
int inline_flag = 0;
bool no_return = expr->call_expr.no_return;
if (expr->call_expr.attr_force_noinline)
{
inline_flag = -1;
@@ -5793,7 +5798,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
LLVMBasicBlockRef after = llvm_basic_block_new(c, "after_call");
FunctionPrototype *default_prototype = type_get_resolved_prototype(default_method->type);
BEValue default_res;
llvm_emit_call_invocation(c, &default_res, target, expr->span, default_prototype, args, values, inline_flag,
llvm_emit_call_invocation(c, &default_res, target, expr->span, default_prototype, args, values, inline_flag, no_return,
llvm_get_ref(c, default_method),
llvm_get_type(c, default_method->type),
varargs);
@@ -5805,7 +5810,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
func_type = llvm_get_type(c, dyn_fn->type);
BEValue normal_res;
values[0] = result;
llvm_emit_call_invocation(c, &normal_res, target, expr->span, prototype, args, values, inline_flag, func, func_type,
llvm_emit_call_invocation(c, &normal_res, target, expr->span, prototype, args, values, inline_flag, no_return, func, func_type,
varargs);
LLVMValueRef normal_val = llvm_load_value(c, &normal_res);
LLVMBasicBlockRef normal_block = c->current_block;
@@ -5830,7 +5835,7 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr
}
llvm_emit_call_invocation(c, result_value, target, expr->span, prototype, args, values, inline_flag, func, func_type,
llvm_emit_call_invocation(c, result_value, target, expr->span, prototype, args, values, inline_flag, no_return, func, func_type,
varargs);
}

View File

@@ -506,7 +506,7 @@ void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignmen
LLVMValueRef llvm_emit_coerce(GenContext *c, LLVMTypeRef coerced, BEValue *value, Type *original_type);
static inline LLVMCallConv llvm_call_convention_from_call(CallABI abi);
void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype *prototype, LLVMTypeRef func_type, LLVMValueRef func, LLVMValueRef *args, unsigned arg_count, int inline_flag, LLVMValueRef error_var, bool sret_return, BEValue *synthetic_return_param);
void llvm_emit_raw_call(GenContext *c, BEValue *result_value, FunctionPrototype *prototype, LLVMTypeRef func_type, LLVMValueRef func, LLVMValueRef *args, unsigned arg_count, int inline_flag, LLVMValueRef error_var, bool sret_return, BEValue *synthetic_return_param, bool no_return);
void llvm_emit_parameter(GenContext *c, LLVMValueRef *args, unsigned *arg_count_ref, ABIArgInfo *info, BEValue *be_value, Type *type);
// -- Dynamic interface --

View File

@@ -1582,7 +1582,7 @@ void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const c
BEValue res;
if (c->debug.builder) llvm_emit_debug_location(c, loc);
llvm_emit_raw_call(c, &res, prototype, llvm_func_type(c, prototype), llvm_get_ref(c, panicf), actual_args,
count, 0, NULL, false, NULL);
count, 0, NULL, false, NULL, true);
llvm_emit_unreachable(c);
return;
}
@@ -1594,7 +1594,7 @@ void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const c
BEValue res;
if (c->debug.builder) llvm_emit_debug_location(c, loc);
llvm_emit_raw_call(c, &res, prototype, llvm_func_type(c, prototype), val.value, actual_args,
count, 0, NULL, false, NULL);
count, 0, NULL, false, NULL, true);
llvm_emit_unreachable(c);
}

View File

@@ -11,7 +11,7 @@
static inline bool sema_analyse_func_macro(SemaContext *context, Decl *decl, AttributeDomain domain, bool *erase_decl);
static inline bool sema_analyse_func(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *erase_decl);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated);
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated, SourceSpan span);
static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl);
static inline bool sema_check_param_uniqueness_and_type(SemaContext *context, Decl **decls, Decl *current,
unsigned current_index, unsigned count);
@@ -1082,7 +1082,7 @@ ERROR:
return decl_poison(decl);
}
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated)
static inline bool sema_analyse_signature(SemaContext *context, Signature *sig, TypeInfo *method_parent, bool is_export, bool is_deprecated, SourceSpan span)
{
Variadic variadic_type = sig->variadic;
Decl **params = sig->params;
@@ -1100,6 +1100,10 @@ static inline bool sema_analyse_signature(SemaContext *context, Signature *sig,
is_macro ? RESOLVE_TYPE_ALLOW_INFER
: RESOLVE_TYPE_DEFAULT)) return false;
rtype = rtype_info->type;
if (sig->attrs.noreturn && !type_is_void(rtype))
{
RETURN_SEMA_ERROR(rtype_info, "@noreturn cannot be used on %s not returning 'void'.", is_macro ? "macros" : "functions");
}
if (sig->attrs.nodiscard)
{
if (type_is_void(rtype))
@@ -1337,7 +1341,7 @@ bool sema_analyse_function_signature(SemaContext *context, Decl *func_decl, Type
bool deprecated = func_decl->resolved_attributes && func_decl->attrs_resolved && func_decl->attrs_resolved->deprecated;
if (!sema_analyse_signature(context, signature, parent, func_decl->is_export, deprecated)) return false;
if (!sema_analyse_signature(context, signature, parent, func_decl->is_export, deprecated, func_decl->span)) return false;
Variadic variadic_type = signature->variadic;
@@ -2875,6 +2879,10 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
decl->func_decl.signature.attrs.always_const = true;
break;
case ATTRIBUTE_NODISCARD:
if (decl->func_decl.signature.attrs.nodiscard)
{
RETURN_SEMA_ERROR(attr, "@nodiscard cannot be combined with @noreturn.");
}
decl->func_decl.signature.attrs.nodiscard = true;
break;
case ATTRIBUTE_MAYDISCARD:
@@ -2885,6 +2893,10 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_
decl->func_decl.attr_noinline = false;
break;
case ATTRIBUTE_NORETURN:
if (decl->func_decl.signature.attrs.nodiscard)
{
RETURN_SEMA_ERROR(attr, "@noreturn cannot be combined with @nodiscard.");
}
decl->func_decl.signature.attrs.noreturn = true;
break;
case ATTRIBUTE_NOSANITIZE:
@@ -3846,7 +3858,7 @@ static inline bool sema_analyse_macro(SemaContext *context, Decl *decl, bool *er
if (!sema_analyse_signature(context, &decl->func_decl.signature,
type_infoptrzero(decl->func_decl.type_parent),
false, deprecated)) return false;
false, deprecated, decl->span)) return false;
if (!decl->func_decl.signature.is_at_macro && decl->func_decl.body_param && !decl->func_decl.signature.is_safemacro)
{

View File

@@ -91,7 +91,6 @@ static bool sema_expr_analyse_enum_add_sub(SemaContext *context, Expr *expr, Exp
static bool sema_expr_analyse_shift(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_and_or(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped);
static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Expr *expr, Expr *left, Expr *right);
@@ -298,8 +297,6 @@ Expr *sema_enter_inline_member(Expr *parent, CanonicalType *type)
Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, unsigned *index_ref)
{
unsigned args = vec_size(context->macro_varargs);
uint64_t index;
Decl *param = NULL;
if (!sema_analyse_expr(context, index_expr)) return poisoned_expr;
if (!type_is_integer(index_expr->type))
{
@@ -954,13 +951,11 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Type *infer_t
Expr *right = exprptr(expr->ternary_expr.else_expr);
if (!sema_analyse_maybe_dead_expr(context, right, path == COND_TRUE, infer_type)) return expr_poison(expr);
bool is_optional = false;
Type *left_canonical = left->type->canonical;
Type *right_canonical = right->type->canonical;
if (left_canonical != right_canonical)
{
Type *max;
max = type_find_max_type(type_no_optional(left_canonical), type_no_optional(right_canonical));
Type *max = type_find_max_type(type_no_optional(left_canonical), type_no_optional(right_canonical));
if (!max)
{
SEMA_ERROR(expr, "Cannot find a common parent type of '%s' and '%s'",
@@ -1039,9 +1034,6 @@ static inline bool sema_identifier_find_possible_inferred(SemaContext *context,
static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, Expr *expr)
{
Decl *ambiguous_decl = NULL;
Decl *private_symbol = NULL;
ASSERT_SPAN(expr, expr && expr->unresolved_ident_expr.ident);
DEBUG_LOG("Resolving identifier '%s'", expr->unresolved_ident_expr.ident);
@@ -1484,7 +1476,6 @@ INLINE bool sema_set_default_argument(SemaContext *context, CalledDecl *callee,
if (arg->resolve_status != RESOLVE_DONE)
{
SemaContext default_context;
Type *rtype = NULL;
SemaContext *new_context = context_transform_for_eval(context, &default_context, param->unit);
bool success;
SCOPE_START
@@ -1632,7 +1623,6 @@ INLINE bool sema_call_evaluate_arguments(SemaContext *context, CalledDecl *calle
// 2. Loop through the parameters.
bool has_named = false;
bool found_splat = false;
ArrayIndex last_index = -1;
Expr *last_named_arg = INVALID_PTR;
Expr *last = NULL;
@@ -1956,7 +1946,7 @@ static inline bool sema_call_analyse_func_invocation(SemaContext *context, Decl
expr->call_expr.has_optional_arg = optional;
if (rtype != type_void)
if (!type_is_void(rtype))
{
bool is_optional_return = type_is_optional(rtype);
expr->call_expr.is_optional_return = is_optional_return;
@@ -2413,6 +2403,10 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
}
call_expr->type = type_add_optional(rtype, optional_return || has_optional_arg);
if (is_no_return && type_is_void(rtype))
{
call_expr->type = type_wildcard;
}
ASSERT_SPAN(call_expr, call_expr->type);
bool must_use = false;
@@ -7827,10 +7821,12 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr)
expr_replace(expr, lhs);
return true;
}
SEMA_ERROR(lhs, "No optional to use '\?\?' with, please remove the '\?\?'.");
RETURN_SEMA_ERROR(lhs, "No optional to use '\?\?' with, please remove the '\?\?'.");
return false;
}
bool active_scope_jump = context->active_scope.jump_end;
// First we analyse the "else" and try to implictly cast.
if (!sema_analyse_expr(context, rhs)) return false;
@@ -7840,6 +7836,9 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr)
return true;
}
// Ignore the jump here.
context->active_scope.jump_end = active_scope_jump;
// Here we might need to insert casts.
Type *else_type = rhs->type;

View File

@@ -3171,6 +3171,7 @@ bool sema_analyse_statement(SemaContext *context, Ast *statement)
{
if (statement->ast_kind == AST_POISONED) return false;
bool dead_code = context->active_scope.jump_end;
unsigned returns = vec_size(context->returns);
if (!sema_analyse_statement_inner(context, statement)) return ast_poison(statement);
if (dead_code)
{
@@ -3187,6 +3188,7 @@ bool sema_analyse_statement(SemaContext *context, Ast *statement)
}
// Remove it
}
vec_resize(context->returns, returns);
statement->ast_kind = AST_NOP_STMT;
}
return true;

View File

@@ -19,7 +19,6 @@ fn void main() {
define void @test.foo() #0 !dbg !8 {
entry:
%values = alloca [1 x i32], align 4
call void @llvm.dbg.declare(metadata ptr %values, metadata !12, metadata !DIExpression()), !dbg !17
store i32 0, ptr %values, align 4, !dbg !17
store i32 0, ptr %values, align 4, !dbg !18
ret void, !dbg !18

View File

@@ -145,21 +145,17 @@ entry:
store i32 %1, ptr %a, align 4, !dbg !26
store i64 0, ptr %a.f, align 8, !dbg !26
br label %loop.cond, !dbg !27
loop.cond: ; preds = %loop.body, %entry
%load.err = load i64, ptr %a.f, align 8, !dbg !28
%result = icmp eq i64 %load.err, 0, !dbg !28
br i1 %result, label %loop.body, label %loop.exit, !dbg !28
loop.body: ; preds = %loop.cond
store i32 2, ptr %a, align 4, !dbg !30
store i64 0, ptr %a.f, align 8, !dbg !30
br label %loop.cond, !dbg !30
loop.exit: ; preds = %loop.cond
ret void, !dbg !30
}
; Function Attrs: nounwind uwtable
define i32 @test.main(ptr %0, i64 %1) #0 !dbg !32 {
entry:
@@ -268,39 +264,30 @@ noerr_block: ; preds = %after_check
%not_err6 = icmp eq i64 %16, 0, !dbg !103
%17 = call i1 @llvm.expect.i1(i1 %not_err6, i1 true), !dbg !103
br i1 %17, label %after_check8, label %assign_optional7, !dbg !103
assign_optional7: ; preds = %noerr_block
store i64 %16, ptr %error_var5, align 8, !dbg !103
br label %guard_block9, !dbg !103
after_check8: ; preds = %noerr_block
br label %noerr_block10, !dbg !103
guard_block9: ; preds = %assign_optional7
br label %voiderr, !dbg !103
noerr_block10: ; preds = %after_check8
%18 = load ptr, ptr %out, align 8, !dbg !104
%19 = call i64 @std.io.File.flush(ptr %18), !dbg !104
%not_err12 = icmp eq i64 %19, 0, !dbg !104
%20 = call i1 @llvm.expect.i1(i1 %not_err12, i1 true), !dbg !104
br i1 %20, label %after_check14, label %assign_optional13, !dbg !104
assign_optional13: ; preds = %noerr_block10
store i64 %19, ptr %error_var11, align 8, !dbg !104
br label %guard_block15, !dbg !104
after_check14: ; preds = %noerr_block10
br label %noerr_block16, !dbg !104
guard_block15: ; preds = %assign_optional13
br label %voiderr, !dbg !104
noerr_block16: ; preds = %after_check14
%21 = load i64, ptr %len, align 8, !dbg !105
%add = add i64 %21, 1, !dbg !105
br label %voiderr, !dbg !96
voiderr: ; preds = %noerr_block16, %guard_block15, %guard_block9, %guard_block
ret ptr null, !dbg !106
}
@@ -395,11 +382,9 @@ entry:
%10 = load i64, ptr %size, align 8, !dbg !160
%i2nb = icmp eq i64 %10, 0, !dbg !160
br i1 %i2nb, label %if.then, label %if.exit, !dbg !160
if.then: ; preds = %entry
store ptr null, ptr %blockret11, align 8, !dbg !163
br label %expr_block.exit, !dbg !163
if.exit: ; preds = %entry
%ptradd = getelementptr inbounds i8, ptr %allocator10, i64 8, !dbg !164
%11 = load i64, ptr %ptradd, align 8, !dbg !164
@@ -407,7 +392,6 @@ if.exit: ; preds = %entry
%type = load ptr, ptr %.cachedtype, align 8
%13 = icmp eq ptr %12, %type
br i1 %13, label %cache_hit, label %cache_miss
cache_miss: ; preds = %if.exit
%ptradd12 = getelementptr inbounds i8, ptr %12, i64 16
%14 = load ptr, ptr %ptradd12, align 8
@@ -415,21 +399,17 @@ cache_miss: ; preds = %if.exit
store ptr %15, ptr %.inlinecache, align 8
store ptr %12, ptr %.cachedtype, align 8
br label %16
cache_hit: ; preds = %if.exit
%cache_hit_fn = load ptr, ptr %.inlinecache, align 8
br label %16
16: ; preds = %cache_hit, %cache_miss
%fn_phi = phi ptr [ %cache_hit_fn, %cache_hit ], [ %15, %cache_miss ]
%17 = icmp eq ptr %fn_phi, null
br i1 %17, label %missing_function, label %match
missing_function: ; preds = %16
%18 = load ptr, ptr @std.core.builtin.panic, align 8, !dbg !166
call void %18(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 6, i32 68), !dbg !166
call void %18(ptr @.panic_msg, i64 44, ptr @.file, i64 16, ptr @.func, i64 6, i32 68) #5, !dbg !166
unreachable, !dbg !166
match: ; preds = %16
%19 = load ptr, ptr %allocator10, align 8
%20 = load i64, ptr %size, align 8
@@ -437,16 +417,13 @@ match: ; preds = %16
%not_err = icmp eq i64 %21, 0, !dbg !166
%22 = call i1 @llvm.expect.i1(i1 %not_err, i1 true), !dbg !166
br i1 %22, label %after_check, label %assign_optional, !dbg !166
assign_optional: ; preds = %match
store i64 %21, ptr %error_var, align 8, !dbg !166
br label %panic_block, !dbg !166
after_check: ; preds = %match
%23 = load ptr, ptr %retparam, align 8, !dbg !166
store ptr %23, ptr %blockret11, align 8, !dbg !166
br label %expr_block.exit, !dbg !166
expr_block.exit: ; preds = %after_check, %if.then
%24 = load ptr, ptr %blockret11, align 8, !dbg !166
store ptr %24, ptr %taddr, align 8
@@ -457,7 +434,6 @@ expr_block.exit: ; preds = %after_check, %if.th
%27 = insertvalue %"char[][]" undef, ptr %25, 0, !dbg !167
%28 = insertvalue %"char[][]" %27, i64 %size13, 1, !dbg !167
br label %noerr_block, !dbg !167
panic_block: ; preds = %assign_optional
%29 = insertvalue %any undef, ptr %error_var, 0, !dbg !167
%30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.anyfault" to i64), 1, !dbg !167
@@ -467,19 +443,16 @@ panic_block: ; preds = %assign_optional
store %"any[]" %"$$temp", ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.panic_msg.1
unreachable, !dbg !154
noerr_block: ; preds = %expr_block.exit
store %"char[][]" %28, ptr %list5, align 8, !dbg !154
!170
store i32 0, ptr %i, align 4, !dbg !171
br label %loop.cond, !dbg !171
loop.cond: ; preds = %loop.exit, %noerr_block
%32 = load i32, ptr %i, align 4, !dbg !172
%33 = load i32, ptr %argc2, align 4, !dbg !173
%lt = icmp slt i32 %32, %33, !dbg !172
br i1 %lt, label %loop.body, label %loop.exit26, !dbg !172
loop.body: ; preds = %loop.cond
!176
%34 = load ptr, ptr %argv3, align 8, !dbg !177
@@ -500,7 +473,6 @@ loop.body: ; preds = %loop.cond
!187
store i64 0, ptr %len18, align 8, !dbg !189
br label %loop.cond19, !dbg !190
loop.cond19: ; preds = %loop.body21, %loop.body
%41 = load ptr, ptr %ptr, align 8, !dbg !191
%42 = load i64, ptr %len18, align 8, !dbg !193
@@ -508,13 +480,11 @@ loop.cond19: ; preds = %loop.body21, %loop.
%43 = load i8, ptr %ptradd20, align 1, !dbg !193
%i2b = icmp ne i8 %43, 0, !dbg !193
br i1 %i2b, label %loop.body21, label %loop.exit, !dbg !193
loop.body21: ; preds = %loop.cond19
%44 = load i64, ptr %len18, align 8, !dbg !194
%add22 = add i64 %44, 1, !dbg !194
store i64 %add22, ptr %len18, align 8, !dbg !194
br label %loop.cond19, !dbg !194
loop.exit: ; preds = %loop.cond19
%45 = load i64, ptr %len18, align 8, !dbg !195
%add23 = add i64 0, %45, !dbg !195
@@ -526,7 +496,6 @@ loop.exit: ; preds = %loop.cond19
%add25 = add i32 %48, 1, !dbg !196
store i32 %add25, ptr %i, align 4, !dbg !196
br label %loop.cond, !dbg !196
loop.exit26: ; preds = %loop.cond
call void @llvm.memcpy.p0.p0.i32(ptr align 8 %list, ptr align 8 %list5, i32 16, i1 false), !dbg !197
%lo = load ptr, ptr %list, align 8, !dbg !198
@@ -537,7 +506,6 @@ loop.exit26: ; preds = %loop.cond
%50 = load ptr, ptr %list, align 8, !dbg !200
call void @std.core.mem.free(ptr %50)
br label %expr_block.exit28, !dbg !202
expr_block.exit28: ; preds = %loop.exit26
%51 = load i32, ptr %blockret, align 4, !dbg !202
ret i32 %51, !dbg !202
@@ -561,25 +529,20 @@ declare void @arena_scratch_end(ptr, i64) #0
define weak ptr @.dyn_search(ptr %0, ptr %1) unnamed_addr {
entry:
br label %check
check: ; preds = %no_match, %entry
%2 = phi ptr [ %0, %entry ], [ %9, %no_match ]
%3 = icmp eq ptr %2, null
br i1 %3, label %missing_function, label %compare
missing_function: ; preds = %check
ret ptr null
compare: ; preds = %check
%4 = getelementptr inbounds
%5 = load ptr, ptr %4, align 8
%6 = icmp eq ptr %5, %1
br i1 %6, label %match, label %no_match
match: ; preds = %compare
%7 = load ptr, ptr %2, align 8
ret ptr %7
no_match: ; preds = %compare
%8 = getelementptr inbounds
%9 = load ptr, ptr %8, align 8
@@ -587,7 +550,6 @@ no_match: ; preds = %compare
}
!llvm.dbg.cu = !{!6}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 2, !"wchar_size", i32 4}

View File

@@ -0,0 +1,39 @@
// #target: macos-x64
module test;
import std;
// Issue #1913
fn void main()
{
char[] bytes = file::load_temp("config.json") ?? abort("Unable to open config.json file");
int hello;
}
/* #expect: test.ll
define void @test.main() #0 {
entry:
%bytes = alloca %"char[]", align 8
%retparam = alloca %"char[]", align 8
%blockret = alloca %"char[]", align 8
%indirectarg = alloca %"any[]", align 8
%hello = alloca i32, align 4
%0 = call i64 @std.io.file.load_temp(ptr %retparam, ptr @.str, i64 11)
%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 %else_block
after_check: ; preds = %entry
%2 = load %"char[]", ptr %retparam, align 8
br label %phi_block
else_block: ; preds = %entry
store %"any[]" zeroinitializer, ptr %indirectarg, align 8
call void @std.core.builtin.panicf(ptr @.str.1, i64 31, ptr @.str.2, i64 19, ptr @.str.3, i64 4, i32 6, ptr byval(%"any[]") align 8 %indirectarg)
call void @llvm.trap()
unreachable
phi_block: ; preds = %after_check
store %"char[]" %2, ptr %bytes, align 8
store i32 0, ptr %hello, align 4
ret void
}

View File

@@ -0,0 +1,8 @@
module test;
import std;
fn void main()
{
char[] bytes = file::load_temp("config.json") ?? {| abort("Unable to open config.json file"); // #error: Cannot find a common type for 'char[]' and 'void'
return {}; |}; // #warning: This code will never execute.
char[] bytes2;
}