From 1d25197bfda25b75ce88727cea0ad7cf4ace8157 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Wed, 6 Aug 2025 14:51:32 +0200 Subject: [PATCH] Bitstructs no longer overloadable with bitops. #2374 --- releasenotes.md | 1 + src/compiler/sema_decls.c | 26 ++++++++++++++++--- src/compiler/sema_expr.c | 9 ++----- .../bitstruct/bitstruct_forbidden_overload.c3 | 14 ++++++++++ 4 files changed, 40 insertions(+), 10 deletions(-) create mode 100644 test/test_suite/bitstruct/bitstruct_forbidden_overload.c3 diff --git a/releasenotes.md b/releasenotes.md index 4c7eff823..e5af31a9d 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -23,6 +23,7 @@ - Fixed bug generating `$c += 1` when `$c` was derived from a pointer but behind a cast. - Compiler segfault when using bitwise not on number literal cast to bitstruct #2373. - Formatter did not properly handle "null" for any, and null for empty faults. #2375 +- Bitstructs no longer overloadable with bitops. #2374 ### Stdlib changes - Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`. diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 7d92607bb..12ac08ae8 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -2059,9 +2059,9 @@ const char *operator_overload_to_string(OperatorOverload operator_overload) case OVERLOAD_ELEMENT_AT: case OVERLOAD_ELEMENT_REF: case OVERLOAD_ELEMENT_SET: - case OVERLOAD_LEN: - case OVERLOAD_NEGATE: - case OVERLOAD_UNARY_MINUS: UNREACHABLE + case OVERLOAD_LEN: UNREACHABLE + case OVERLOAD_NEGATE: return "~"; + case OVERLOAD_UNARY_MINUS: return "-"; case OVERLOAD_PLUS: return "+"; case OVERLOAD_MINUS: return "-"; case OVERLOAD_MULTIPLY: return "*"; @@ -2445,6 +2445,26 @@ INLINE bool sema_analyse_operator_method(SemaContext *context, Type *parent_type return false; } + if (parent_type->canonical->type_kind == TYPE_BITSTRUCT) + { + switch (operator) + { + case OVERLOAD_XOR: + case OVERLOAD_AND: + case OVERLOAD_OR: + case OVERLOAD_XOR_ASSIGN: + case OVERLOAD_AND_ASSIGN: + case OVERLOAD_OR_ASSIGN: + case OVERLOAD_NEGATE: + { + SourceSpan span = method_find_overload_span(method); + RETURN_SEMA_ERROR_AT(span, "Bitstructs do not support overloading the '%s' operator.", + operator_overload_to_string(operator)); + } + default: + break; + } + } // Check that actual types match up Type *value; Type *index_type; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index fb9aedde0..193469a14 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -6961,6 +6961,7 @@ static bool sema_expr_analyse_op_assign_enum_ptr(SemaContext *context, Expr *rhs } return true; } + /** * Analyse *= /= %= ^= |= &= += -= <<= >>= * @@ -7026,12 +7027,7 @@ static bool sema_expr_analyse_op_assign(SemaContext *context, Expr *expr, Expr * Type *canonical = no_fail->canonical; if (type_is_user_defined(canonical)) { - if (canonical->type_kind == TYPE_BITSTRUCT) - { - if (operator == BINARYOP_BIT_OR_ASSIGN - || operator == BINARYOP_BIT_AND_ASSIGN - || operator == BINARYOP_BIT_XOR_ASSIGN) goto SKIP_OVERLOAD_CHECK; - } + if (canonical->type_kind == TYPE_BITSTRUCT && is_bit_op) goto SKIP_OVERLOAD_CHECK; BoolErr b = sema_insert_overload_in_op_assign_or_error(context, expr, left, right, operator, no_fail->canonical); if (b == BOOL_ERR) return false; if (b == BOOL_TRUE) return true; @@ -8589,7 +8585,6 @@ VALID_VEC: // 3. The simple case, non-const. if (!expr_const_foldable_unary(inner, UNARYOP_BITNEG)) { - expr->type = inner->type; return true; } diff --git a/test/test_suite/bitstruct/bitstruct_forbidden_overload.c3 b/test/test_suite/bitstruct/bitstruct_forbidden_overload.c3 new file mode 100644 index 000000000..3f86c5926 --- /dev/null +++ b/test/test_suite/bitstruct/bitstruct_forbidden_overload.c3 @@ -0,0 +1,14 @@ +bitstruct Foo : uint +{ + bool test : 2; +} + +fn bool Foo.test(self, Foo other) @operator(==) => true; + +fn Foo Foo.and(self, uint other) @operator(&) => (Foo)(((uint)self) & other); // #error: Bitstructs do not support +fn Foo Foo.or(self, uint other) @operator(|) => (Foo)(((uint)self) | other); // #error: Bitstructs do not support + +fn void Foo.and_eq(&self, uint other) @operator(&=) => *self = (Foo)(((uint)*self) & other); // #error: Bitstructs do not support +fn void Foo.or_eq(&self, uint other) @operator(|=) => *self = (Foo)(((uint)*self) | other); // #error: Bitstructs do not support + +fn Foo Foo.neg(self) @operator(~) { return {}; } // #error: Bitstructs do not support \ No newline at end of file