Resolving &X.b when X is a const incorrectly checked for runtime constness #2842

Creating a generic instance fails if it is created after interface checking #2840
This commit is contained in:
Christoffer Lerno
2026-01-25 21:24:27 +01:00
parent 3c04a326f4
commit 4899ee14e2
6 changed files with 52 additions and 15 deletions

View File

@@ -133,6 +133,7 @@
- Packed .c3l files without compressions weren't unpacked correctly.
- Lowering of optional in && was incorrect #2843
- Resolving &X.b when X is a const incorrectly checked for runtime constness #2842
- Alignment param on $$unaligned_* not checked for zero #2844
### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -37,7 +37,7 @@ static bool sema_expr_analyse_syscall(SemaContext *context, Expr *expr);
static inline bool sema_expr_analyse_swizzle(SemaContext *context, Expr *expr, bool swizzle_two);
static inline int builtin_expected_args(BuiltinFunction func);
static inline bool is_valid_atomicity(SemaContext *context, Expr *expr);
static bool sema_check_alignment_expression(SemaContext *context, Expr *align);
static bool sema_check_alignment_expression(SemaContext *context, Expr *align, bool may_be_zero);
static bool sema_expr_is_valid_mask_for_value(SemaContext *context, Expr *expr, Expr *value)
{
@@ -78,15 +78,16 @@ static bool sema_check_builtin_args_const(SemaContext *context, Expr **args, siz
return true;
}
static bool sema_check_alignment_expression(SemaContext *context, Expr *align)
static bool sema_check_alignment_expression(SemaContext *context, Expr *align, bool may_be_zero)
{
if (!sema_analyse_expr_rhs(context, type_usz, align, false, NULL, false)) return false;
if (!expr_is_const_int(align)
|| !int_fits(align->const_expr.ixx, TYPE_U64)
|| (!is_power_of_two(align->const_expr.ixx.i.low) && align->const_expr.ixx.i.low))
{
RETURN_SEMA_ERROR(align, "Expected a constant power-of-two alignment or zero.");
RETURN_SEMA_ERROR(align, may_be_zero ? "Expected a constant power-of-two alignment or zero." : "Expected a constant power-of-two alignment.");
}
if (!may_be_zero && align->const_expr.ixx.i.low == 0) RETURN_SEMA_ERROR(align, "Alignment must not be zero.");
return true;
}
@@ -258,7 +259,7 @@ static bool sema_expr_analyse_compare_exchange(SemaContext *context, Expr *expr)
RETURN_SEMA_ERROR(args[6], "Failure ordering may not be RELEASE / ACQUIRE_RELEASE.");
}
Expr *align = args[7];
if (!sema_check_alignment_expression(context, align)) return false;
if (!sema_check_alignment_expression(context, align, true)) return false;
expr->type = type_add_optional(args[1]->type, optional);
return true;
}
@@ -1049,7 +1050,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
type_get_vector(pointer_type->pointer, flat_pointer_vec->type_kind, len)),
type_quoted_error_string(args[2]->type));
}
if (!sema_check_alignment_expression(context, args[3])) return false;
if (!sema_check_alignment_expression(context, args[3], true)) return false;
if (!sema_expr_is_valid_mask_for_value(context, args[1], args[2])) return false;
rtype = type_get_vector(pointer_type->pointer, flat_pointer_vec->type_kind, len);
break;
@@ -1072,7 +1073,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
type_get_vector_from_vector(pointer_type->pointer, flat_pointer_vec)),
type_quoted_error_string(args[2]->type));
}
if (!sema_check_alignment_expression(context, args[3])) return false;
if (!sema_check_alignment_expression(context, args[3], true)) return false;
if (!sema_expr_is_valid_mask_for_value(context, args[2], args[1])) return false;
rtype = type_void;
break;
@@ -1125,7 +1126,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
{
RETURN_SEMA_ERROR(args[2], "Expected the value to be of type %s.", type_quoted_error_string(pointer_type->pointer));
}
if (!sema_check_alignment_expression(context, args[3])) return false;
if (!sema_check_alignment_expression(context, args[3], true)) return false;
if (!sema_expr_is_valid_mask_for_value(context, args[1], args[2])) return false;
rtype = pointer_type->pointer;
break;
@@ -1140,7 +1141,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
{
RETURN_SEMA_ERROR(args[2], "Expected the value to be of type %s.", type_quoted_error_string(pointer_type->pointer));
}
if (!sema_check_alignment_expression(context, args[3])) return false;
if (!sema_check_alignment_expression(context, args[3], true)) return false;
if (!sema_expr_is_valid_mask_for_value(context, args[2], args[1])) return false;
rtype = type_void;
break;
@@ -1217,7 +1218,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER, BA_INTEGER, BA_BOOL}, 3)) return false;
Type *original = type_flatten(args[0]->type);
if (original == type_voidptr) RETURN_SEMA_ERROR(args[0], "Expected a typed pointer.");
if (!sema_check_alignment_expression(context, args[1])) return false;
if (!sema_check_alignment_expression(context, args[1], false)) return false;
if (!sema_cast_const(args[2])) RETURN_SEMA_ERROR(args[2], "'is_volatile' must be a compile time constant.");
rtype = original->pointer;
break;
@@ -1228,7 +1229,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_check_builtin_args(context, args, (BuiltinArg[]) {BA_POINTER}, 1)) return false;
if (!sema_check_builtin_args(context, &args[2], (BuiltinArg[]) {BA_INTEGER, BA_BOOL}, 2)) return false;
Type *original = type_flatten(args[0]->type);
if (!sema_check_alignment_expression(context, args[2])) return false;
if (!sema_check_alignment_expression(context, args[2], false)) return false;
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "'is_volatile' must be a compile time constant.");
if (original != type_voidptr)
{
@@ -1282,7 +1283,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
if (!is_valid_atomicity(context, args[3])) return false;
if (args[3]->const_expr.ixx.i.low == ATOMIC_UNORDERED) RETURN_SEMA_ERROR(args[3], "'unordered' is not valid ordering.");
if (!sema_check_alignment_expression(context, args[4])) return false;
if (!sema_check_alignment_expression(context, args[4], true)) return false;
rtype = args[1]->type;
break;
}
@@ -1302,7 +1303,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
if (!is_valid_atomicity(context, args[3])) return false;
if (args[3]->const_expr.ixx.i.low == ATOMIC_UNORDERED) RETURN_SEMA_ERROR(args[3], "'unordered' is not valid ordering.");
if (!sema_check_alignment_expression(context, args[4])) return false;
if (!sema_check_alignment_expression(context, args[4], true)) return false;
rtype = args[1]->type;
break;
}
@@ -1321,7 +1322,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
if (!is_valid_atomicity(context, args[3])) return false;
if (args[3]->const_expr.ixx.i.low == ATOMIC_UNORDERED) RETURN_SEMA_ERROR(args[3], "'unordered' is not valid ordering.");
if (!sema_check_alignment_expression(context, args[4])) return false;
if (!sema_check_alignment_expression(context, args[4], true)) return false;
rtype = args[1]->type;
break;
}
@@ -1341,7 +1342,7 @@ bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr)
if (!sema_cast_const(args[3])) RETURN_SEMA_ERROR(args[3], "Ordering must be a compile time constant.");
if (!is_valid_atomicity(context, args[3])) return false;
if (args[3]->const_expr.ixx.i.low == ATOMIC_UNORDERED) RETURN_SEMA_ERROR(args[3], "'unordered' is not valid ordering.");
if (!sema_check_alignment_expression(context, args[4])) return false;
if (!sema_check_alignment_expression(context, args[4], true)) return false;
rtype = args[1]->type;
break;
}

View File

@@ -5374,7 +5374,29 @@ FOUND:;
break;
}
}
ASSERT(stage < ANALYSIS_INTERFACE);
if (stage < ANALYSIS_INTERFACE) goto EXIT;
if (compiler.context.errors_found) return poisoned_decl;
FOREACH(Decl *, decl, copied)
{
SemaContext context_gen;
switch (decl->decl_kind)
{
case DECL_TYPEDEF:
case DECL_STRUCT:
case DECL_UNION:
case DECL_ENUM:
case DECL_BITSTRUCT:
break;
default:
continue;
}
if (decl->interfaces)
{
sema_context_init(&context_gen, decl->unit);
sema_check_interfaces(&context_gen, decl);
sema_context_destroy(&context_gen);
}
}
EXIT:;
if (compiler.context.errors_found) return poisoned_decl;
}

View File

@@ -143,6 +143,7 @@ bool sema_analyse_attributes(SemaContext *context, Decl *decl, Attr **attrs, Att
void unit_register_optional_global_decl(CompilationUnit *unit, Decl *decl);
bool analyse_func_body(SemaContext *context, Decl *decl);
bool sema_check_interfaces(SemaContext *context, Decl *decl);
INLINE bool sema_analyse_stmt_chain(SemaContext *context, Ast *statement)
{

View File

@@ -0,0 +1,8 @@
import std;
fn int foo() => 0;
alias FooFn = fn int();
enum Bar : const FooFn
{
FOO = fn () => (int)(iptr)ExclusiveRange{int}.typeid,
BAR = &foo,
}

View File

@@ -0,0 +1,4 @@
fn void unaligned_load_store(void* dst, void* src) @nostrip
{
$$unaligned_store(dst, $$unaligned_load((char*)src, 2, false), 0, false); // #error: Alignment must not be zero
}