diff --git a/releasenotes.md b/releasenotes.md index a76042666..d046f15b9 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -14,6 +14,7 @@ - Added `$$unaligned_load` and `$$unaligned_store`. - `--no-headers` option to suppress creating headers when generating a library. - Support c-file compilation in libraries. +- Allow using $defined(&a[1]) to check if the operation is supported. ### Fixes - Error with unsigned compare in `@ensure` when early returning 0 #1207. diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 931874c29..cf9359a85 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -2752,7 +2752,8 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, assert(expr->expr_kind == EXPR_SUBSCRIPT || expr->expr_kind == EXPR_SUBSCRIPT_ADDR); bool is_checking = eval_type == SUBSCRIPT_EVAL_VALID; - if (is_checking) eval_type = SUBSCRIPT_EVAL_VALUE; + if (is_checking) eval_type = expr->expr_kind == EXPR_SUBSCRIPT_ADDR + ? SUBSCRIPT_EVAL_REF : SUBSCRIPT_EVAL_VALUE; // 1. Evaluate the expression to index. Expr *subscripted = exprptr(expr->subscript_expr.expr); @@ -2826,6 +2827,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, { if (eval_type == SUBSCRIPT_EVAL_REF) { + if (is_checking) goto VALID_FAIL_POISON; RETURN_SEMA_ERROR(subscripted, "You need to use && to take the address of a temporary."); } // 4a. This may either be an initializer list or a CT value @@ -2835,6 +2837,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, // 4b. Now we need to check that we actually have a valid type. if (index_value < 0) { + if (is_checking) goto VALID_FAIL_POISON; RETURN_SEMA_ERROR(index, "To subscript an untyped list a compile time integer index is needed."); } if (eval_type == SUBSCRIPT_EVAL_ASSIGN) TODO; @@ -2857,10 +2860,10 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, &index_type, &overload)) { - SEMA_ERROR(expr, - "A function or macro with '@operator(&[])' is not defined for %s, so you need && to take the address of the temporary.", - type_quoted_error_string(subscripted->type)); - return false; + if (is_checking) goto VALID_FAIL_POISON; + RETURN_SEMA_ERROR(expr, "A function or macro with '@operator(&[])' is not defined for %s, " + "so you need && to take the address of the temporary.", + type_quoted_error_string(subscripted->type)); } } if (is_checking) goto VALID_FAIL_POISON; @@ -2874,8 +2877,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (!len) { if (is_checking) goto VALID_FAIL_POISON; - SEMA_ERROR(subscripted, "Cannot index '%s' from the end, since there is no 'len' overload.", type_to_error_string(subscripted->type)); - return false; + RETURN_SEMA_ERROR(subscripted, "Cannot index '%s' from the end, since there is no 'len' overload.", type_to_error_string(subscripted->type)); } if (!sema_analyse_expr(context, current_expr)) return false; Decl *temp = decl_new_generated_var(current_expr->type, VARDECL_PARAM, current_expr->span); @@ -6298,6 +6300,15 @@ static inline bool sema_expr_analyse_addr(SemaContext *context, Expr *expr, bool goto REDO; case EXPR_SUBSCRIPT: inner->expr_kind = EXPR_SUBSCRIPT_ADDR; + if (failed_ref) + { + if (!sema_expr_analyse_subscript(context, inner, SUBSCRIPT_EVAL_VALID)) return false; + if (!expr_ok(inner)) + { + *failed_ref = true; + return false; + } + } if (!sema_analyse_expr_lvalue_fold_const(context, inner)) return false; expr_replace(expr, inner); return true; diff --git a/test/test_suite/compile_time_introspection/defined_index.c3t b/test/test_suite/compile_time_introspection/defined_index.c3t new file mode 100644 index 000000000..3e6a3476f --- /dev/null +++ b/test/test_suite/compile_time_introspection/defined_index.c3t @@ -0,0 +1,29 @@ +// #target: macos-x64 +module test; +struct Abc { int x; } +fn int* Abc.get(&self, usz index) @operator(&[]) { return &self.x; } + +struct Bcd { int x; } +fn int Bcd.get(&self, usz index) @operator([]) { return 1; } + +fn void main() +{ + Abc a; + Bcd b; + int[4] c; + bool a1 = $defined(&a[0]); + bool a2 = $defined(a[0]); + bool b1 = $defined(&b[0]); + bool b2 = $defined(b[0]); + bool c1 = $defined(&c[0]); + bool c2 = $defined(c[0]); +} + +/* #expect: test.ll + + store i8 1, ptr %a1, align 1 + store i8 0, ptr %a2, align 1 + store i8 0, ptr %b1, align 1 + store i8 1, ptr %b2, align 1 + store i8 1, ptr %c1, align 1 + store i8 1, ptr %c2, align 1 \ No newline at end of file