Bump version to 0.3.14. Better non-lvalue errors. Dereferenced optional pointers are not lvalues.

This commit is contained in:
Christoffer Lerno
2022-08-12 00:13:44 +02:00
parent b1c78edc5e
commit 571728a42e
11 changed files with 155 additions and 66 deletions

View File

@@ -97,58 +97,65 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type, V
}
const char *decl_to_name(Decl *decl)
{
const char *name = decl_to_a_name(decl);
if (name[1] == 'n') return &name[3];
return &name[2];
}
const char *decl_to_a_name(Decl *decl)
{
switch (decl->decl_kind)
{
case DECL_BODYPARAM:
return "bodyparam";
return "a bodyparam";
case DECL_DECLARRAY:
return "declarray";
return "a declarray";
case DECL_BITSTRUCT:
return "bitstruct";
return "a bitstruct";
case DECL_POISONED:
return "poisoned decl";
return "a poisoned decl";
case DECL_CT_ASSERT:
return "compile time assert";
return "a compile time assert";
case DECL_CT_CASE:
return "compile time case";
return "a compile time case";
case DECL_CT_ELIF:
return "compile time else if";
return "a compile time else if";
case DECL_CT_ELSE:
return "compile time else";
return "a compile time else";
case DECL_CT_IF:
return "compile time if";
return "a compile time if";
case DECL_CT_SWITCH:
return "compile time switch";
return "a compile time switch";
case DECL_IMPORT:
return "import";
return "an import";
case DECL_LABEL:
return "label";
return "a label";
case DECL_ATTRIBUTE:
return "attribute";
return "an attribute";
case DECL_DEFINE:
case DECL_TYPEDEF:
return "define";
return "a define";
case DECL_DISTINCT:
return "distinct type";
return "a distinct type";
case DECL_ENUM:
return "enum";
return "an enum";
case DECL_ENUM_CONSTANT:
return "enum value";
return "an enum value";
case DECL_FAULTVALUE:
return "err value";
return "a fault value";
case DECL_FAULT:
return "fault";
return "a fault";
case DECL_FUNC:
return "function";
return "a function";
case DECL_GENERIC:
return "generic";
return "a generic";
case DECL_MACRO:
return "macro";
return "a macro";
case DECL_STRUCT:
return "struct";
return "a struct";
case DECL_UNION:
return "union";
return "a union";
case DECL_VAR:
switch (decl->var.kind)
{
@@ -156,30 +163,30 @@ const char *decl_to_name(Decl *decl)
case VARDECL_REWRAPPED:
UNREACHABLE
case VARDECL_CONST:
return "constant";
return "a constant";
case VARDECL_GLOBAL:
return "global variable";
return "a global variable";
case VARDECL_LOCAL:
return "variable";
return "a variable";
case VARDECL_PARAM:
return "parameter";
return "a parameter";
case VARDECL_MEMBER:
case VARDECL_BITMEMBER:
return "member";
return "a member";
case VARDECL_PARAM_CT:
return "compile time parameter";
return "a compile time parameter";
case VARDECL_PARAM_CT_TYPE:
return "compile time type parameter";
return "a compile time type parameter";
case VARDECL_PARAM_REF:
return "ref parameter";
return "a ref parameter";
case VARDECL_PARAM_EXPR:
return "expression parameter";
return "a expression parameter";
case VARDECL_LOCAL_CT:
return "compile time variable";
return "a compile time variable";
case VARDECL_LOCAL_CT_TYPE:
return "compile time type variable";
return "a compile time type variable";
case VARDECL_UNWRAPPED:
return "unwrapped";
return "an unwrapped variable";
}
UNREACHABLE
}

View File

@@ -1907,6 +1907,7 @@ Decl *decl_new_var(const char *name, SourceSpan span, TypeInfo *type, VarDeclKin
Decl *decl_new_generated_var(Type *type, VarDeclKind kind, SourceSpan span);
void decl_set_external_name(Decl *decl);
const char *decl_to_name(Decl *decl);
const char *decl_to_a_name(Decl *decl);
INLINE bool decl_ok(Decl *decl);
INLINE bool decl_poison(Decl *decl);

View File

@@ -558,7 +558,7 @@ int sema_check_comp_time_bool(SemaContext *context, Expr *expr)
}
bool expr_is_lvalue(Expr *expr)
static bool sema_check_expr_lvalue(Expr *top_expr, Expr *expr)
{
switch (expr->expr_kind)
{
@@ -566,9 +566,17 @@ bool expr_is_lvalue(Expr *expr)
return true;
case EXPR_IDENTIFIER:
{
if (expr->identifier_expr.is_const) return false;
if (expr->identifier_expr.is_const)
{
SEMA_ERROR(top_expr, "You cannot assign to a constant.");
return false;
}
Decl *decl = expr->identifier_expr.decl;
if (decl->decl_kind != DECL_VAR) return false;
if (decl->decl_kind != DECL_VAR)
{
SEMA_ERROR(top_expr, "You cannot assign a value to %s.", decl_to_a_name(decl));
return false;
}
decl = decl_raw(decl);
switch (decl->var.kind)
{
@@ -578,33 +586,96 @@ bool expr_is_lvalue(Expr *expr)
case VARDECL_GLOBAL:
case VARDECL_PARAM:
case VARDECL_PARAM_REF:
return true;
case VARDECL_CONST:
case VARDECL_MEMBER:
case VARDECL_BITMEMBER:
case VARDECL_PARAM_CT:
case VARDECL_PARAM_CT_TYPE:
return true;
case VARDECL_CONST:
case VARDECL_PARAM_EXPR:
return false;
UNREACHABLE
case VARDECL_MEMBER:
case VARDECL_BITMEMBER:
goto ERR;
case VARDECL_UNWRAPPED:
case VARDECL_ERASE:
case VARDECL_REWRAPPED:
UNREACHABLE
}
UNREACHABLE
}
case EXPR_UNARY:
return expr->unary_expr.operator == UNARYOP_DEREF;
if (expr->unary_expr.operator != UNARYOP_DEREF) goto ERR;
if (IS_OPTIONAL(expr))
{
SEMA_ERROR(top_expr, "You cannot assign to a dereferenced optional.");
return false;
}
return true;
case EXPR_BITACCESS:
case EXPR_ACCESS:
return expr_is_lvalue(expr->access_expr.parent);
return sema_check_expr_lvalue(top_expr, expr->access_expr.parent);
case EXPR_GROUP:
return expr_is_lvalue(expr->inner_expr);
return sema_check_expr_lvalue(top_expr, expr->inner_expr);
case EXPR_SUBSCRIPT:
case EXPR_SLICE:
case EXPR_SUBSCRIPT_ADDR:
if (IS_OPTIONAL(expr))
{
SEMA_ERROR(top_expr, "You cannot assign to an optional value.");
return false;
}
return true;
default:
case EXPR_HASH_IDENT:
SEMA_ERROR(top_expr, "You cannot assign to an unevaluated expression.");
return false;
case EXPR_POISONED:
case EXPR_BITASSIGN:
case EXPR_BINARY:
case EXPR_BUILTIN:
case EXPR_COMPILER_CONST:
case EXPR_MACRO_BODY_EXPANSION:
case EXPR_CALL:
case EXPR_CAST:
case EXPR_CATCH:
case EXPR_CATCH_UNWRAP:
case EXPR_COMPOUND_LITERAL:
case EXPR_CONST:
case EXPR_CT_CALL:
case EXPR_CT_CONV:
case EXPR_CT_EVAL:
case EXPR_COND:
case EXPR_DECL:
case EXPR_DESIGNATOR:
case EXPR_EXPR_BLOCK:
case EXPR_EXPRESSION_LIST:
case EXPR_FAILABLE:
case EXPR_RETHROW:
case EXPR_FORCE_UNWRAP:
case EXPR_MACRO_BLOCK:
case EXPR_RETVAL:
case EXPR_FLATPATH:
case EXPR_INITIALIZER_LIST:
case EXPR_DESIGNATED_INITIALIZER_LIST:
case EXPR_POST_UNARY:
case EXPR_SLICE_ASSIGN:
case EXPR_STRINGIFY:
case EXPR_ARGV_TO_SUBARRAY:
case EXPR_TERNARY:
case EXPR_TRY:
case EXPR_TRY_UNWRAP:
case EXPR_TRY_UNWRAP_CHAIN:
case EXPR_TYPEID:
case EXPR_TYPEINFO:
case EXPR_VARIANTSWITCH:
case EXPR_NOP:
case EXPR_TYPEID_INFO:
case EXPR_VARIANT:
case EXPR_BUILTIN_ACCESS:
goto ERR;
}
UNREACHABLE
ERR:
SEMA_ERROR(top_expr, "An assignable expression, like a variable, was expected here.");
return false;
}
@@ -703,11 +774,7 @@ bool expr_may_addr(Expr *expr)
bool sema_expr_check_assign(SemaContext *c, Expr *expr)
{
if (!expr_is_lvalue(expr))
{
SEMA_ERROR(expr, "An assignable expression, like a variable, was expected here.");
return false;
}
if (!sema_check_expr_lvalue(expr, expr)) return false;
if (expr->expr_kind == EXPR_BITACCESS || expr->expr_kind == EXPR_ACCESS) expr = expr->access_expr.parent;
if (expr->expr_kind == EXPR_IDENTIFIER)
{

View File

@@ -56,7 +56,6 @@ bool splitpathref(const char *string, ArraySize len, Path **path_ref, const char
#define IS_CONST(_x) ((_x)->expr_kind == EXPR_CONST)
bool expr_is_lvalue(Expr *expr);
bool sema_expr_check_assign(SemaContext *c, Expr *expr);
bool sema_analyse_contracts(SemaContext *context, AstId doc, AstId **asserts);
void sema_append_contract_asserts(AstId assert_first, Ast* compound_stmt);

View File

@@ -1 +1 @@
#define COMPILER_VERSION "0.3.13"
#define COMPILER_VERSION "0.3.14"