diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index d34ae0918..de1440ffb 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -505,10 +505,10 @@ struct TempState TempAllocator* old; TempAllocator* current; usz mark; -}/* -/+++ +} +<* Push the current temp allocator. A push must always be balanced with a pop using the current state. -+++/ */ +*> fn TempState temp_push(TempAllocator* other = null) { TempAllocator* current = allocator::temp(); diff --git a/releasenotes.md b/releasenotes.md index 95b368ee9..cd703e60c 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,8 @@ - Interfaces now support .ptr and .type directly without casting to `any`. - Switch to `<* *>` docs. - Improve error messages on expressions like `var $type = int;` #1553. +- Disallow casting a `void*` to `any` or an interface, unless it is `null`. +- Defer resolution of declarations when looked up in `def` aliased #1559. ### Fixes - `Unsupported int[*] $x = { 1, 2, 3, 4 }` #1489. diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 5d2ecc309..65a24938c 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -724,6 +724,14 @@ static TypeCmpResult match_pointers(CastContext *cc, Type *to_ptr, Type *from_pt return type_is_pointer_equivalent(cc->context, to_ptr, from_ptr, flatten); } +static bool rule_voidptr_to_any(CastContext *cc, bool is_explicit, bool is_silent) +{ + if (expr_is_const_pointer(cc->expr) && !cc->expr->const_expr.ptr) return true; + RETURN_CAST_ERROR(cc->expr, + "Casting a 'void*' to %s is not permitted (except when the 'void*' is a constant null).", + type_quoted_error_string(cc->to)); +} + static bool rule_ptr_to_ptr(CastContext *cc, bool is_explicit, bool is_silent) { if (is_explicit) return true; @@ -1129,7 +1137,6 @@ static bool rule_ptr_to_interface(CastContext *cc, bool is_explicit, bool is_sil if (type_may_implement_interface(pointee)) { Type *interface = cc->to; - Decl *pointee_decl = pointee->decl; if (type_implements_interface(cc, pointee->decl, interface)) return true; } if (is_silent) return false; @@ -2283,7 +2290,9 @@ static void cast_typeid_to_bool(SemaContext *context, Expr *expr, Type *to_type) #define RULST &rule_ulist_to_struct /* Untyped list -> bitstruct or union */ #define RULAR &rule_ulist_to_vecarr /* Untyped list -> vector or array */ #define RULFE &rule_ulist_to_inferred /* Untyped list -> inferred vector or array */ -#define RULSL &rule_ulist_to_slice /* Untyped list -> slice */ +#define RULSL &rule_ulist_to_slice /* Untyped list -> slice */ +#define RVPAN &rule_voidptr_to_any /* void* -> interface/any */ + CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = { // void, wildc, bool, int, float, ptr, slice, vec, bitst, distc, array, strct, union, any, infc, fault, enum, func, typid, afaul, voidp, arrpt, infer, ulist (to) {_NA__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // VOID (from) @@ -2306,7 +2315,7 @@ CastRule cast_rules[CONV_LAST + 1][CONV_LAST + 1] = { {REXPL, _NO__, REXPL, RPTIN, _NO__, _NO__, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RPTPT, _NO__, _NO__, ROKOK, _NO__, _NO__, _NO__}, // FUNC {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NA__, _NO__, REXPL, REXPL, _NO__, _NO__}, // TYPEID {REXPL, _NO__, REXPL, RPTIN, _NO__, REXPL, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, _NO__, _NO__, RAFFA, _NO__, _NO__, _NO__, _NA__, REXPL, REXPL, _NO__, _NO__}, // ANYFAULT - {REXPL, _NO__, REXPL, RPTIN, _NO__, ROKOK, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, _NO__, ROKOK, _NO__, _NO__, _NA__, ROKOK, _NO__, _NO__}, // VOIDPTR + {REXPL, _NO__, REXPL, RPTIN, _NO__, ROKOK, _NO__, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, RVPAN, RVPAN, _NO__, _NO__, ROKOK, _NO__, _NO__, _NA__, ROKOK, _NO__, _NO__}, // VOIDPTR {REXPL, _NO__, REXPL, RPTIN, _NO__, RPTPT, RAPSL, REXVC, _NO__, RXXDI, _NO__, _NO__, _NO__, ROKOK, ROKOK, _NO__, _NO__, _NO__, _NO__, _NO__, ROKOK, RPTPT, RPTFE, _NO__}, // ARRPTR {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__}, // INFERRED {_NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RULSL, RULAR, RULST, RXXDI, RULAR, RULST, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, _NO__, RULFE, _NO__}, // UNTYPED_LIST diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index e40c04ffa..5a3c7b7e9 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -4299,7 +4299,16 @@ Decl *sema_analyse_parameterized_identifier(SemaContext *c, Path *decl_path, con return poisoned_decl; } } - if (!sema_analyse_decl(c, symbol)) return poisoned_decl; + + CompilationUnit *unit = symbol->unit; + if (unit->module->stage < ANALYSIS_POST_REGISTER) + { + vec_add(unit->global_decls, symbol); + } + else + { + if (!sema_analyse_decl(c, symbol)) return poisoned_decl; + } unit_register_external_symbol(c, symbol); return symbol; } @@ -4345,6 +4354,7 @@ static inline bool sema_analyse_define(SemaContext *context, Decl *decl, bool *e RETURN_SEMA_ERROR(expr, "A global variable or function name was expected here."); } Decl *symbol = expr->identifier_expr.decl; + if (!sema_analyse_decl(context, symbol)) return false; bool should_be_const = char_is_upper(decl->name[0]); if (should_be_const) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index ecbf6eb83..ace65414c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -729,7 +729,6 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) { Decl *decl = expr->identifier_expr.decl; decl = decl_flatten(decl); - switch (decl->decl_kind) { case DECL_FNTYPE: diff --git a/test/test_suite/any/casting_voidptr_to_any.c3 b/test/test_suite/any/casting_voidptr_to_any.c3 new file mode 100644 index 000000000..154abb335 --- /dev/null +++ b/test/test_suite/any/casting_voidptr_to_any.c3 @@ -0,0 +1,26 @@ +module mylib::ifaces; +interface IOp { + fn void op(); +} +module mylib(); +import std::io; +import mylib::ifaces; +struct Op (IOp){ + Type data; +} +fn void Op.op(&self) @dynamic => io::printn("op"); +module myapp; +import mylib; +fn void test(void* tptr){ + // this work + IOp iop = (Op()*)tptr; + iop.op(); + + // this don't work + iop = tptr; // #error: Casting a 'void*' to 'IOp' is not permitted + iop.op(); +} +fn void! main(String[] args) { + Op()* t = mem::new(Op(), {.data = 1}); + test(&t); +} diff --git a/test/unit/regression/any.c3 b/test/unit/regression/any.c3 index 120f05d0a..f3324bec7 100644 --- a/test/unit/regression/any.c3 +++ b/test/unit/regression/any.c3 @@ -5,14 +5,8 @@ fn void any_compare() int x; any a = &x; any b = &x; - void* v = &x; - any c = v; assert(a == b); assert(a == a); - assert(a.ptr == c.ptr); - assert(a != c); - bool aisc = a == c; - assert(!aisc); } def AnyAlias = any;