"poison" the current function early when a declaration can't be correctly resolved.

This commit is contained in:
Christoffer Lerno
2025-07-19 20:49:26 +02:00
parent 2053f2767b
commit 694d297eb8
8 changed files with 45 additions and 23 deletions

View File

@@ -25,6 +25,7 @@
- Allow even smaller memory limits.
- Check unaligned array access.
- Add "@structlike" for typedefs.
- "poison" the current function early when a declaration can't be correctly resolved.
### Fixes
- mkdir/rmdir would not work properly with substring paths on non-windows platforms.

View File

@@ -4639,6 +4639,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
VarDeclKind kind = decl->var.kind;
bool success = true;
bool is_global = !local;
switch (kind)
{
@@ -4811,25 +4812,26 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
CallEnvKind env_kind = context->call_env.kind;
if (is_static) context->call_env.kind = CALL_ENV_FUNCTION_STATIC;
decl->in_init = true;
if (!sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false, true, NULL))
{
context->call_env.kind = env_kind;
return decl_poison(decl);
}
success = sema_expr_analyse_assign_right_side(context, NULL, decl->type, init, false, true, NULL);
decl->in_init = false;
context->call_env.kind = env_kind;
if (infer_len)
{
if (!success) return decl_poison(decl);
decl->type = type_add_optional(init->type, IS_OPTIONAL(decl));
}
// 2. Check const-ness
if (global_level_var && !expr_is_runtime_const(init))
if (global_level_var)
{
SEMA_ERROR(init, "The expression must be a constant value.");
return decl_poison(decl);
if (!success) return decl_poison(decl);
if (!expr_is_runtime_const(init))
{
SEMA_ERROR(init, "The expression must be a constant value.");
return decl_poison(decl);
}
}
if (!success) goto EXIT_OK;
if (global_level_var || !type_is_abi_aggregate(init->type)) sema_cast_const(init);
if (expr_is_const(init))
{
@@ -4850,7 +4852,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local)
{
if (!sema_set_alloca_alignment(context, decl->type, &decl->alignment)) return false;
}
return true;
return success;
}

View File

@@ -1232,7 +1232,11 @@ static inline bool sema_analyse_declare_stmt(SemaContext *context, Ast *statemen
Decl *decl = statement->declare_stmt;
VarDeclKind kind = decl->var.kind;
bool erase = kind == VARDECL_LOCAL_CT_TYPE || kind == VARDECL_LOCAL_CT;
if (!sema_analyse_var_decl(context, decl, true)) return false;
if (!sema_analyse_var_decl(context, decl, true))
{
if (!decl_ok(decl)) context->active_scope.is_poisoned = true;
return false;
}
if (erase || decl->decl_kind == DECL_ERASED) statement->ast_kind = AST_NOP_STMT;
return true;
}
@@ -1445,6 +1449,7 @@ static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement)
if (is_infinite && !statement->for_stmt.flow.has_break)
{
if (!success) context->active_scope.is_poisoned = true;
SET_JUMP_END(context, statement);
}
return success;

View File

@@ -442,7 +442,7 @@ fn void test_file(Path file_path)
// Start process
SubProcess compilation = process::create(cmdline.array_view(), { .search_user_path, .no_window, .inherit_environment })!!;
defer compilation.destroy();
CInt result = compilation.join()!!;
CInt result = compilation.join() ?? 1;
DString out;
io::copy_to(&&compilation.stderr(), &out)!!;
if (result != 0 && result != 1)

View File

@@ -25,13 +25,15 @@ struct BazTwo
fn void test()
{
Foo x;
Bar y = (Bar)(x); // #error: 'Foo' to 'Bar'
{ Bar y = (Bar)(x); } // #error: 'Foo' to 'Bar'
Baz z;
int[2] w = (int[2])(z); // #error: 'Baz' to 'int[2]'
z = (Baz)(w);
BazTwo v = (BazTwo)(z); // #error: 'Baz' to 'BazTwo'
v = (BazTwo)(w);
z = (Baz)(v);
w = (int[2])(v);
{ int[2] w = (int[2])(z); } // #error: 'Baz' to 'int[2]'
int[2] w;
z = (Baz)(w); // #error: to 'Baz'
{ BazTwo v = (BazTwo)(z); } // #error: 'Baz' to 'BazTwo'
BazTwo v;
v = (BazTwo)(w); // #error: to 'BazTwo'
z = (Baz)(v); // #error: possible to cast 'BazTwo' to 'Baz'
w = (int[2])(v); // #error: possible to cast 'BazTwo' to 'int[2]'
}

View File

@@ -10,6 +10,18 @@ $foreach $c : $chars:
int $offset = ($c - $from) / BITS;
int $rem = ($c - $from) % BITS;
uint128 $value = $bitmap[$offset]; // #error: is out of range
$endforeach
}
fn int main2()
{
String $chars = "Abcd";
char $from = 2;
char[10] $bitmap = {};
$foreach $c : $chars:
int $offset = ($c - $from) / BITS;
int $rem = ($c - $from) % BITS;
uint128 $value = 1;
$value |= 1ULL << $rem;
$bitmap = $bitmap[:$offset] +++ $value +++ $bitmap[$offset+1..]; // #error: End index out of bounds
$endforeach

View File

@@ -1,14 +1,14 @@
module testing;
import std::io;
macro char[] read(src, Allocator allocator, n)
macro void read(src, Allocator allocator, n)
{
char* data = allocator::malloc_try(allocator, n)!; // #error: Rethrow is only allowed in macros
io::read_all(src, data[:n])!;
(void)io::read_all(src, data[:n]);
}
fn void main()
{
ByteReader br;
read(&br, allocator::temp(), 10);
read(&br, allocator::temp(), 10)!!;
}

View File

@@ -27,7 +27,7 @@ import abc @norecurse @public;
fn int test()
{
Abc x; // #error: is '@private'
{ Abc x; } // #error: is '@private'
abc::baz::test(); // #error: is '@private'
return 0;
}