diff --git a/releasenotes.md b/releasenotes.md index fc75cf051..27e40afa0 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -33,6 +33,7 @@ - Change CBool to be 1 byte. - `any_to_int` checks value to be int and no longer works with enum. - Add check in formatter printing "%c". +- Fix bug where `!!` and `!` was not recognized to jump out of the current scope. ### Stdlib changes - Increase BitWriter.write_bits limit up to 32 bits. diff --git a/src/compiler/c_codegen.c b/src/compiler/c_codegen.c index c4a08a35d..b137e20f6 100644 --- a/src/compiler/c_codegen.c +++ b/src/compiler/c_codegen.c @@ -395,6 +395,7 @@ static void c_emit_expr(GenContext *c, CValue *value, Expr *expr) { switch (expr->expr_kind) { + case EXPR_PTR_ACCESS: case EXPR_EXT_TRUNC: break; case EXPR_ACCESS: diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 34362a658..a0b79f548 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -3380,6 +3380,7 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc) case EXPR_DEFAULT_ARG: case EXPR_TYPECALL: case EXPR_MEMBER_GET: + case EXPR_PTR_ACCESS: break; } } @@ -3591,6 +3592,15 @@ INLINE void expr_rewrite_const_typeid(Expr *expr, Type *type) expr->resolve_status = RESOLVE_DONE; } +INLINE void expr_rewrite_ptr_access(Expr *expr, Type *type) +{ + Expr *inner = expr_copy(expr); + expr->expr_kind = EXPR_PTR_ACCESS; + expr->inner_expr = inner; + expr->type = type; +} + + INLINE void expr_rewrite_ext_trunc(Expr *expr, Type *type, bool is_signed) { Expr *inner = expr_copy(expr); diff --git a/src/compiler/copying.c b/src/compiler/copying.c index d6e2ab3fc..1fef317e1 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -472,6 +472,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) case EXPR_OPTIONAL: case EXPR_SPLAT: case EXPR_STRINGIFY: + case EXPR_PTR_ACCESS: MACRO_COPY_EXPR(expr->inner_expr); return expr; case EXPR_DEFAULT_ARG: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 9c92089bc..24fb119a4 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -534,7 +534,6 @@ typedef enum typedef enum { - CAST_ANYPTR, CAST_ANYBOOL, CAST_APTSA, CAST_ARRVEC, @@ -562,7 +561,6 @@ typedef enum CAST_PTRPTR, CAST_PTRINT, CAST_SLBOOL, - CAST_SAPTR, CAST_SLSL, CAST_SLARR, CAST_STRPTR, @@ -798,6 +796,7 @@ typedef enum EXPR_OTHER_CONTEXT, EXPR_POINTER_OFFSET, EXPR_POISONED, + EXPR_PTR_ACCESS, EXPR_POST_UNARY, EXPR_RETHROW, EXPR_RETVAL, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index daa5f13f6..b5e86b00f 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -82,6 +82,7 @@ bool expr_may_addr(Expr *expr) return true; case EXPR_BENCHMARK_HOOK: case EXPR_TEST_HOOK: + case EXPR_PTR_ACCESS: return false; case NON_RUNTIME_EXPR: case EXPR_ASM: @@ -185,6 +186,7 @@ bool expr_is_runtime_const(Expr *expr) case EXPR_MEMBER_GET: case EXPR_BITACCESS: case EXPR_COND: + case EXPR_PTR_ACCESS: return false; case EXPR_ACCESS: expr = expr->access_expr.parent; @@ -335,7 +337,6 @@ static inline bool expr_cast_is_runtime_const(Expr *expr) case CAST_ERROR: UNREACHABLE case CAST_INTENUM: - case CAST_ANYPTR: case CAST_EUBOOL: case CAST_EUER: case CAST_EREU: @@ -357,7 +358,6 @@ static inline bool expr_cast_is_runtime_const(Expr *expr) case CAST_INTPTR: case CAST_PTRPTR: case CAST_APTSA: - case CAST_SAPTR: case CAST_SLSL: case CAST_VOID: case CAST_ANYBOOL: @@ -604,6 +604,8 @@ bool expr_is_pure(Expr *expr) case EXPR_BENCHMARK_HOOK: case EXPR_TEST_HOOK: return false; + case EXPR_PTR_ACCESS: + return expr_is_pure(expr->inner_expr); case EXPR_EXT_TRUNC: return expr_is_pure(expr->ext_trunc_expr.inner); case EXPR_OTHER_CONTEXT: diff --git a/src/compiler/json_output.c b/src/compiler/json_output.c index 9059bc0f6..1d3e57b3d 100644 --- a/src/compiler/json_output.c +++ b/src/compiler/json_output.c @@ -243,13 +243,17 @@ void print_var_expr(FILE *file, Expr *expr) switch (expr->expr_kind) { - case EXPR_BITASSIGN: + case EXPR_BITASSIGN: case EXPR_BITACCESS: case EXPR_ACCESS: print_var_expr(file, expr->access_expr.parent); fputs(".", file); print_var_expr(file, expr->access_expr.child); break; + case EXPR_PTR_ACCESS: + print_var_expr(file, expr->access_expr.parent); + fputs(".ptr", file); + break; case EXPR_EXT_TRUNC: TODO case EXPR_BINARY: diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 96afcdd2d..5f3c0978e 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1468,9 +1468,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu value->value = LLVMBuildIsNotNull(c->builder, value->value, "anybool"); value->kind = BE_BOOLEAN; break; - case CAST_ANYPTR: - llvm_emit_any_pointer(c, value, value); - break; case CAST_ERROR: UNREACHABLE case CAST_STRPTR: @@ -1484,10 +1481,6 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu case CAST_APTSA: llvm_emit_arr_to_slice_cast(c, value, to_type); break; - case CAST_SAPTR: - llvm_value_fold_optional(c, value); - llvm_emit_slice_pointer(c, value, value); - break; case CAST_EREU: // This is a no op. ASSERT0(type_lowering(to_type) == type_lowering(from_type)); @@ -6147,8 +6140,8 @@ static void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr { ASSERT0(arg_count); Expr *any_val = args[0]; - ASSERT0(any_val->expr_kind == EXPR_CAST); - args[0] = exprptr(any_val->cast_expr.expr); + ASSERT0(any_val->expr_kind == EXPR_PTR_ACCESS); + args[0] = any_val->inner_expr; } if (!expr->call_expr.is_func_ref) @@ -7200,6 +7193,21 @@ void llvm_emit_expr_global_value(GenContext *c, BEValue *value, Expr *expr) ASSERT0(!llvm_value_is_addr(value)); } +static void llvm_emit_ptr_access(GenContext *c, BEValue *value, Expr *expr) +{ + llvm_emit_expr(c, value, expr->inner_expr); + llvm_value_fold_optional(c, value); + if (value->kind == BE_ADDRESS) + { + AlignSize alignment; + LLVMValueRef ptr = llvm_emit_struct_gep_raw(c, value->value, llvm_get_type(c, value->type), 0, value->alignment, &alignment); + llvm_value_set_address(value, ptr, expr->type, alignment); + return; + } + LLVMValueRef ptr = llvm_emit_extract_value(c, value->value, 0); + llvm_value_set(value, ptr, expr->type); +} + static void llvm_emit_ext_trunc(GenContext *c, BEValue *value, Expr *expr) { llvm_emit_expr(c, value, expr->ext_trunc_expr.inner); @@ -7229,6 +7237,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_MEMBER_GET: case EXPR_NAMED_ARGUMENT: UNREACHABLE + case EXPR_PTR_ACCESS: + llvm_emit_ptr_access(c, value, expr); + return; case EXPR_EXT_TRUNC: llvm_emit_ext_trunc(c, value, expr); return; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 2b2d11bf0..dbbe09ac2 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1479,7 +1479,11 @@ static void cast_fault_to_int(SemaContext *context, Expr *expr, Type *type) } static void cast_typeid_to_ptr(SemaContext *context, Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_IDPTR, type); } static void cast_any_to_bool(SemaContext *context, Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_ANYBOOL, type); } -static void cast_any_to_ptr(SemaContext *context, Expr *expr, Type *type) { insert_runtime_cast(expr, CAST_ANYPTR, type); } +static void cast_any_to_ptr(SemaContext *context, Expr *expr, Type *type) +{ + expr_rewrite_ptr_access(expr, type); +} + static void cast_all_to_void(SemaContext *context, Expr *expr, Type *to_type) { insert_runtime_cast(expr, CAST_VOID, type_void); } static void cast_retype(SemaContext *context, Expr *expr, Type *to_type) { expr->type = to_type; } @@ -1911,7 +1915,8 @@ static void cast_slice_to_ptr(SemaContext *context, Expr *expr, Type *type) expr->type = type; return; } - insert_runtime_cast(expr, CAST_SAPTR, type); + + expr_rewrite_ptr_access(expr, type); } /** diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 3307e6fc5..01058036c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -569,6 +569,7 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp case EXPR_LAST_FAULT: case EXPR_MEMBER_GET: case EXPR_NAMED_ARGUMENT: + case EXPR_PTR_ACCESS: goto ERR; } UNREACHABLE @@ -596,6 +597,7 @@ static bool expr_may_ref(Expr *expr) case EXPR_TYPECALL: case EXPR_MEMBER_GET: case EXPR_EXT_TRUNC: + case EXPR_PTR_ACCESS: return false; case EXPR_OTHER_CONTEXT: return expr_may_ref(expr->expr_other_context.inner); @@ -7650,7 +7652,6 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) "but the function does not allow optional results. Did you mean to use '!!' instead?"); } } - return true; } @@ -8929,6 +8930,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr case EXPR_MEMBER_GET: case EXPR_SPLAT: case EXPR_EXT_TRUNC: + case EXPR_PTR_ACCESS: if (!sema_analyse_expr(active_context, main_expr)) return false; break; } @@ -9306,6 +9308,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, case EXPR_TRY_UNWRAP_CHAIN: case EXPR_TYPEID_INFO: UNREACHABLE + case EXPR_PTR_ACCESS: + return sema_analyse_expr(context, expr->inner_expr); case EXPR_EXT_TRUNC: return sema_analyse_expr(context, expr->ext_trunc_expr.inner); case EXPR_SPLAT: diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index e493e0478..d7a61156f 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -325,6 +325,7 @@ RETRY: case EXPR_FORCE_UNWRAP: case EXPR_RETHROW: case EXPR_OPTIONAL: + case EXPR_PTR_ACCESS: expr = expr->inner_expr; goto RETRY; case EXPR_DEFAULT_ARG: diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index b564bfa0b..f63d4dadf 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -739,6 +739,7 @@ static inline bool sema_expr_valid_try_expression(Expr *expr) case EXPR_ASM: case EXPR_DEFAULT_ARG: case EXPR_EXT_TRUNC: + case EXPR_PTR_ACCESS: return true; } UNREACHABLE @@ -1189,6 +1190,24 @@ static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement) if (!sema_expr_check_discard(context, expr)) return false; switch (expr->expr_kind) { + case EXPR_RETHROW: + if (expr->rethrow_expr.inner->expr_kind == EXPR_OPTIONAL) + { + context->active_scope.jump_end = true; + } + break; + case EXPR_FORCE_UNWRAP: + if (expr->inner_expr->expr_kind == EXPR_OPTIONAL) + { + context->active_scope.jump_end = true; + } + break; + case EXPR_POST_UNARY: + if (expr->rethrow_expr.inner->expr_kind == EXPR_OPTIONAL) + { + context->active_scope.jump_end = true; + } + break; case EXPR_CALL: if (expr->call_expr.no_return) context->active_scope.jump_end = true; break;