diff --git a/src/compiler/dwarf.h b/src/compiler/dwarf.h index 89677362a..7434a17c5 100644 --- a/src/compiler/dwarf.h +++ b/src/compiler/dwarf.h @@ -1,4 +1,6 @@ #pragma once +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCUnusedMacroInspection" // Copyright (c) 2019 Christoffer Lerno. All rights reserved. // Use of this source code is governed by the GNU LGPLv3.0 license @@ -281,4 +283,6 @@ #define DW_CFA_lo_user 0x1c #define DW_CFA_hi_user 0x3f -#define DWARF_PRODUCER_NAME "c3c" \ No newline at end of file +#define DWARF_PRODUCER_NAME "c3c" + +#pragma clang diagnostic pop \ No newline at end of file diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 8b8937733..acdd5b954 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -572,6 +572,7 @@ int sema_check_comp_time_bool(SemaContext *context, Expr *expr) return expr->const_expr.b; } + bool expr_is_ltype(Expr *expr) { switch (expr->expr_kind) @@ -621,6 +622,24 @@ bool expr_is_ltype(Expr *expr) } } +bool sema_expr_check_assign(SemaContext *c, Expr *expr) +{ + if (!expr_is_ltype(expr)) + { + SEMA_ERROR(expr, "An assignable expression, like a variable, was expected here."); + return false; + } + if (expr->expr_kind == EXPR_IDENTIFIER) expr->identifier_expr.decl->var.is_written = true; + if (expr->expr_kind != EXPR_UNARY) return true; + Expr *inner = expr->inner_expr; + if (inner->expr_kind != EXPR_IDENTIFIER) return true; + Decl *decl = inner->identifier_expr.decl; + if (decl->decl_kind != DECL_VAR) return true; + if (!decl->var.may_not_write) return true; + SEMA_ERROR(inner, "'in' parameters may not be assigned to."); + return false; +} + static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) { Decl *decl = expr->identifier_expr.decl; @@ -4432,13 +4451,7 @@ static bool sema_expr_analyse_assign(SemaContext *context, Expr *expr, Expr *lef // 2. Check assignability - if (!expr_is_ltype(left)) - { - SEMA_ERROR(left, "This expression is not assignable, did you make a mistake?"); - return false; - } - - if (left->expr_kind == EXPR_IDENTIFIER) left->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, left)) return false; bool is_unwrapped_var = expr_is_unwrapped_ident(left); @@ -4508,13 +4521,7 @@ static bool sema_expr_analyse_common_assign(SemaContext *context, Expr *expr, Ex if (!sema_analyse_expr_lvalue(context, left)) return false; // 2. Verify that the left side is assignable. - if (!expr_is_ltype(left)) - { - SEMA_ERROR(left, "Expression is not assignable."); - return false; - } - - if (left->expr_kind == EXPR_IDENTIFIER) left->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, left)) return false; Type *no_fail = type_no_fail(left->type); @@ -4607,13 +4614,7 @@ static bool sema_expr_analyse_add_sub_assign(SemaContext *context, Expr *expr, E if (!sema_analyse_expr(context, left)) return false; // 2. Ensure the left hand side is assignable - if (!expr_is_ltype(left)) - { - SEMA_ERROR(left, "Expression is not assignable."); - return false; - } - - if (left->expr_kind == EXPR_IDENTIFIER) left->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, left)) return false; Type *left_type_canonical = left->type->canonical; @@ -5196,13 +5197,7 @@ static bool sema_expr_analyse_shift_assign(SemaContext *context, Expr *expr, Exp bool failable = IS_FAILABLE(left) || IS_FAILABLE(right); // 2. Ensure the lhs side is assignable - if (!expr_is_ltype(left)) - { - SEMA_ERROR(left, "Expression is not assignable."); - return false; - } - - if (left->expr_kind == EXPR_IDENTIFIER) left->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, left)) return false; // 3. Only integers may be shifted. if (!both_any_integer_or_integer_vector(left, right)) return sema_type_error_on_binop(expr); @@ -5812,13 +5807,7 @@ static inline bool sema_expr_analyse_incdec(SemaContext *context, Expr *expr) if (!sema_analyse_expr_lvalue(context, inner)) return false; // 2. Assert it's an l-value - if (!expr_is_ltype(inner)) - { - SEMA_ERROR(inner, "An assignable expression, like a variable, was expected here."); - return false; - } - - if (inner->expr_kind == EXPR_IDENTIFIER) inner->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, inner)) return false; // 3. This might be a $foo, if to handle it. if (inner->expr_kind == EXPR_CT_IDENT) @@ -7068,6 +7057,17 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr) case EXPR_IDENTIFIER: if (!sema_cast_ident_rvalue(context, expr)) return false; break; + case EXPR_UNARY: + { + if (expr->unary_expr.operator != UNARYOP_DEREF) break; + Expr *inner = expr->inner_expr; + if (inner->expr_kind != EXPR_IDENTIFIER) break; + Decl *decl = inner->identifier_expr.decl; + if (decl->decl_kind != DECL_VAR) break; + if (!decl->var.may_not_read) break; + SEMA_ERROR(expr, "'out' parameters may not be read."); + return false; + } default: break; } diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index 66b53452b..bcdf2f67e 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -58,6 +58,7 @@ bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *bod AttributeType sema_analyse_attribute(SemaContext *context, Attr *attr, AttributeDomain domain); bool expr_is_ltype(Expr *expr); +bool sema_expr_check_assign(SemaContext *c, Expr *expr); void sema_context_init(SemaContext *context, CompilationUnit *unit); void sema_context_destroy(SemaContext *context); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index ceb71c8ea..af5d32a32 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -254,13 +254,7 @@ static inline bool sema_analyse_try_unwrap(SemaContext *context, Expr *expr) if (!sema_analyse_expr_lvalue(context, ident)) return false; // 3b. Make sure it's assignable - if (!expr_is_ltype(ident)) - { - SEMA_ERROR(ident, "'try' expected an assignable variable or expression here, did you make a mistake?"); - return false; - } - - if (ident->expr_kind == EXPR_IDENTIFIER) ident->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, ident)) return false; // 3c. It can't be failable either. if (IS_FAILABLE(ident)) @@ -393,13 +387,7 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr) { if (!sema_analyse_expr_lvalue(context, ident)) return false; - if (!expr_is_ltype(ident)) - { - SEMA_ERROR(ident, "'catch' expected an assignable variable or expression here, did you make a mistake?"); - return false; - } - - if (ident->expr_kind == EXPR_IDENTIFIER) ident->identifier_expr.decl->var.is_written = true; + if (!sema_expr_check_assign(context, ident)) return false; if (ident->type->canonical != type_anyerr) { @@ -1064,7 +1052,6 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen bool is_variable = false; if (expr_is_ltype(enumerator)) { - if (enumerator->expr_kind == EXPR_IDENTIFIER) { enumerator->identifier_expr.decl->var.is_written = true; diff --git a/test/test_suite/errors/try_with_chained_unwrap_errors.c3 b/test/test_suite/errors/try_with_chained_unwrap_errors.c3 index cfadc2bf9..272b46519 100644 --- a/test/test_suite/errors/try_with_chained_unwrap_errors.c3 +++ b/test/test_suite/errors/try_with_chained_unwrap_errors.c3 @@ -9,7 +9,7 @@ fn void test2() int! a; int b; if (try b = a) {} - if (try test2 = a) {} // #error: 'try' expected an assignable variable or expression here, did you make a mistake? + if (try test2 = a) {} // #error: An assignable expression } const int BAZ = 1; @@ -19,7 +19,7 @@ fn void test3() int! a; int b; - if (try BAZ = a) {} // #error: 'try' expected an assignable variable or expression here, did you make a mistake? + if (try BAZ = a) {} // #error: An assignable expression } diff --git a/test/test_suite/expressions/arithmetics_sema_fail.c3 b/test/test_suite/expressions/arithmetics_sema_fail.c3 index a7de80b31..ffb6dda03 100644 --- a/test/test_suite/expressions/arithmetics_sema_fail.c3 +++ b/test/test_suite/expressions/arithmetics_sema_fail.c3 @@ -17,32 +17,32 @@ fn void test9() fn void test10() { - 10 = 20; // #error: This expression is not assignable + 10 = 20; // #error: An assignable expression } fn void test11() { - '10' = '20'; // #error: This expression is not assignable + '10' = '20'; // #error: An assignable expression } fn void test12() { - true = false; // #error: This expression is not assignable + true = false; // #error: An assignable expression } fn void test13() { - "a" = "b"; // #error: This expression is not assignable + "a" = "b"; // #error: An assignable expression } fn void test14() { - 1.2 = 1.3; // #error: This expression is not assignable + 1.2 = 1.3; // #error: An assignable expression } fn void test15() { - null = null; // #error: This expression is not assignable + null = null; // #error: An assignable expression } fn void test16() diff --git a/test/test_suite/expressions/assignability.c3 b/test/test_suite/expressions/assignability.c3 index 16e1e7396..aeed1330d 100644 --- a/test/test_suite/expressions/assignability.c3 +++ b/test/test_suite/expressions/assignability.c3 @@ -2,34 +2,34 @@ define Number = int; fn void test1() { - 10 = 20; // #error: This expression is not assignable + 10 = 20; // #error: An assignable expression } fn void test2() { - "foo" = "bar"; // #error: This expression is not assignable + "foo" = "bar"; // #error: An assignable expression } fn void test3() { - true = false; // #error: This expression is not assignable + true = false; // #error: An assignable expression } fn void test4() { - 'c' = 'd'; // #error: This expression is not assignable + 'c' = 'd'; // #error: An assignable expression } fn void test5() { - 3.14 = 2.14; // #error: This expression is not assignable + 3.14 = 2.14; // #error: An assignable expression } fn void test21() { int a = 0; int b = 2; - a++ = b++; // #error: This expression is not assignable + a++ = b++; // #error: An assignable expression } fn void test22() diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 index 0fc59b0b2..f78a6ae5e 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -62,7 +62,7 @@ fn void test9() { const char A = 1; char b = A; - A = b; // #error: This expression is not assignable, did you make + A = b; // #error: An assignable expression } fn void test10()