diff --git a/releasenotes.md b/releasenotes.md index cd7b94925..38c79be37 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -69,6 +69,7 @@ - Missing end padding when including a packed struct #1966. - Issue when scalar expanding a boolean from a conditional to a bool vector #1954. - Fix issue when parsing bitstructs, preventing them from implementing interfaces. +- Regression `String! a; char* b = a.ptr;` would incorrectly be allowed. ### Stdlib changes - Added '%h' and '%H' for printing out binary data in hexadecimal using the formatter. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7f07edda6..ea291741a 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -3784,7 +3784,7 @@ INLINE void expr_rewrite_ptr_access(Expr *expr, Expr *inner, Type *type) ASSERT(inner->resolve_status == RESOLVE_DONE); expr->expr_kind = EXPR_PTR_ACCESS; expr->inner_expr = inner; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(inner)); expr->resolve_status = RESOLVE_DONE; } @@ -3794,7 +3794,7 @@ INLINE void expr_rewrite_enum_from_ord(Expr *expr, Type *type) ASSERT(inner->resolve_status == RESOLVE_DONE); expr->expr_kind = EXPR_ENUM_FROM_ORD; expr->inner_expr = inner; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(expr)); expr->resolve_status = RESOLVE_DONE; } @@ -3819,7 +3819,7 @@ INLINE void expr_rewrite_int_to_bool(Expr *expr, bool negate) Expr *inner = expr_copy(expr); expr->expr_kind = EXPR_INT_TO_BOOL; expr->int_to_bool_expr = (ExprIntToBool) { .inner = inner, .negate = negate }; - expr->type = type_bool; + expr->type = type_add_optional(type_bool, IS_OPTIONAL(expr)); } INLINE void expr_rewrite_ext_trunc(Expr *expr, Type *type, bool is_signed) @@ -3827,7 +3827,7 @@ INLINE void expr_rewrite_ext_trunc(Expr *expr, Type *type, bool is_signed) Expr *inner = expr_copy(expr); expr->expr_kind = EXPR_EXT_TRUNC; expr->ext_trunc_expr = (ExprExtTrunc) { .inner = inner, .is_signed = is_signed }; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(inner)); } INLINE void expr_rewrite_const_int(Expr *expr, Type *type, uint64_t v) @@ -3869,7 +3869,7 @@ INLINE void expr_rewrite_to_int_to_float(Expr *expr, Type *type) Expr *inner = expr_copy(expr); expr->expr_kind = EXPR_INT_TO_FLOAT; expr->inner_expr = inner; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(inner)); } INLINE void expr_rewrite_to_int_to_ptr(Expr *expr, Type *type) @@ -3877,7 +3877,7 @@ INLINE void expr_rewrite_to_int_to_ptr(Expr *expr, Type *type) Expr *inner = expr_copy(expr); expr->expr_kind = EXPR_INT_TO_PTR; expr->inner_expr = inner; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(inner)); } INLINE void expr_rewrite_to_ptr_to_int(Expr *expr, Type *type) @@ -3885,7 +3885,7 @@ INLINE void expr_rewrite_to_ptr_to_int(Expr *expr, Type *type) Expr *inner = expr_copy(expr); expr->expr_kind = EXPR_PTR_TO_INT; expr->inner_expr = inner; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(inner)); } INLINE void expr_rewrite_to_float_to_int(Expr *expr, Type *type) @@ -3893,7 +3893,7 @@ INLINE void expr_rewrite_to_float_to_int(Expr *expr, Type *type) Expr *inner = expr_copy(expr); expr->expr_kind = EXPR_FLOAT_TO_INT; expr->inner_expr = inner; - expr->type = type; + expr->type = type_add_optional(type, IS_OPTIONAL(inner)); } INLINE void expr_rewrite_const_float(Expr *expr, Type *type, Real d) @@ -4108,9 +4108,11 @@ INLINE bool check_module_name(Path *path) #ifdef NDEBUG #define ASSERT_SPANF(node__, check__, format__, ...) do { } while(0) #define ASSERT_SPAN(node__, check__) do { } while(0) +#define ASSERT_AT(span__, check__) do { } while(0) #else #define ASSERT_SPANF(node__, check__, format__, ...) do { if (!(check__)) { assert_print_line((node__)->span); eprintf(format__, __VA_ARGS__); ASSERT(check__); } } while(0) #define ASSERT_SPAN(node__, check__) do { if (!(check__)) { assert_print_line((node__)->span); ASSERT(check__); } } while(0) +#define ASSERT_AT(span__, check__) do { if (!(check__)) { assert_print_line(span__); ASSERT(check__); } } while(0) #endif void assert_print_line(SourceSpan span); diff --git a/src/compiler/llvm_codegen_value.c b/src/compiler/llvm_codegen_value.c index 8a45903a6..7d1dcb674 100644 --- a/src/compiler/llvm_codegen_value.c +++ b/src/compiler/llvm_codegen_value.c @@ -115,7 +115,7 @@ void llvm_value_rvalue(GenContext *c, BEValue *value) void llvm_emit_jump_to_optional_exit(GenContext *c, LLVMValueRef opt_value) { - ASSERT(c->catch.block && "unexpected emit"); + ASSERT_AT(c->last_emitted_loc, c->catch.block && "unexpected emit"); bool is_constant_opt = llvm_is_const(opt_value); // Maybe we don't need to emit anything? diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f1f0e50fe..1d72fd92a 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -255,23 +255,24 @@ static inline void context_switch_stat_pop(SemaContext *swapped, ContextSwitchSt Expr *sema_enter_inline_member(Expr *parent, CanonicalType *type) { + Expr *expr; switch (type->type_kind) { case TYPE_STRUCT: { Decl *decl = type->decl; if (!decl->is_substruct) return NULL; - Expr *embedded_struct = expr_access_inline_member(parent, decl); - return embedded_struct; + expr = expr_access_inline_member(parent, decl); + break; } case TYPE_DISTINCT: { Decl *decl = type->decl; if (!decl->is_substruct) return NULL; - Expr *inner_expr = expr_copy(parent); + expr = expr_copy(parent); type = type->decl->distinct->type; - inner_expr->type = type; - return inner_expr; + expr->type = type; + break; } case TYPE_ENUM: { @@ -282,28 +283,31 @@ Expr *sema_enter_inline_member(Expr *parent, CanonicalType *type) { if (decl->enums.inline_value) { - Expr *expr = expr_new_expr(EXPR_CONST, parent); + expr = expr_new_expr(EXPR_CONST, parent); expr_rewrite_const_int(expr, decl->enums.type_info->type, parent->const_expr.enum_err_val->enum_constant.ordinal); return expr; } - return copy_expr_single(parent->const_expr.enum_err_val->enum_constant.args[decl->enums.inline_index]); + expr = copy_expr_single(parent->const_expr.enum_err_val->enum_constant.args[decl->enums.inline_index]); + break; } if (decl->enums.inline_value) { - Expr *expr = copy_expr_single(parent); - expr->type = decl->enums.type_info->type; - return expr; + expr = copy_expr_single(parent); + expr->type = type_add_optional(decl->enums.type_info->type, IS_OPTIONAL(parent)); + break; } - Expr *property = expr_new(EXPR_ACCESS_RESOLVED, parent->span); - property->resolve_status = RESOLVE_DONE; - property->access_resolved_expr.parent = parent; - property->access_resolved_expr.ref = decl->enums.parameters[decl->enums.inline_value]; - property->type = property->access_resolved_expr.ref->type; - return property; + expr = expr_new(EXPR_ACCESS_RESOLVED, parent->span); + expr->resolve_status = RESOLVE_DONE; + expr->access_resolved_expr.parent = parent; + expr->access_resolved_expr.ref = decl->enums.parameters[decl->enums.inline_value]; + expr->type = expr->access_resolved_expr.ref->type; + break; } default: return NULL; } + if (IS_OPTIONAL(parent)) expr->type = type_add_optional(expr->type, true); + return expr; } Expr *sema_expr_analyse_ct_arg_index(SemaContext *context, Expr *index_expr, unsigned *index_ref) @@ -406,7 +410,7 @@ Expr *expr_access_inline_member(Expr *parent, Decl *parent_decl) embedded_struct->resolve_status = RESOLVE_DONE; embedded_struct->access_resolved_expr.parent = parent; embedded_struct->access_resolved_expr.ref = parent_decl->strukt.members[0]; - embedded_struct->type = embedded_struct->access_resolved_expr.ref->type; + embedded_struct->type = type_add_optional(embedded_struct->access_resolved_expr.ref->type, IS_OPTIONAL(parent)); return embedded_struct; } diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index bffe22a3b..91457bab1 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -480,8 +480,8 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E { RETURN_SEMA_ERROR(element, "An untyped list can only have " "constant elements, you can try " - "to type the list by prefixing the type, " - "e.g. 'int[2] { a, b }'."); + "to type the list by prefixing the type and possibly enclosing it in parentheses, " + "e.g. '((int[2]){ a, b })'."); } } initializer->expr_kind = EXPR_CONST; diff --git a/test/test_suite/expressions/opt_in_conv.c3 b/test/test_suite/expressions/opt_in_conv.c3 new file mode 100644 index 000000000..3989ac32b --- /dev/null +++ b/test/test_suite/expressions/opt_in_conv.c3 @@ -0,0 +1,9 @@ +module test; +import std; +fn void main() +{ + String s = "Hello"; + Char16* title = String.to_new_utf16(s).ptr; // #error: It is not possible to cast from + int! a; + float b = (float)a; // #error: It is not possible to cast from +} \ No newline at end of file