From af4309b286646cb610737037e1648b989e1c53fa Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 1 Sep 2025 10:44:19 +0200 Subject: [PATCH] $defined returns an error when assigning a struct initializer with an incorrect type #2449 --- releasenotes.md | 1 + src/compiler/compiler_internal.h | 4 +- src/compiler/sema_decls.c | 4 +- src/compiler/sema_expr.c | 72 ++++++------ src/compiler/sema_initializers.c | 106 +++++++++++------- src/compiler/sema_stmts.c | 2 +- .../defined_inits.c3t | 23 ++++ 7 files changed, 135 insertions(+), 77 deletions(-) create mode 100644 test/test_suite/compile_time_introspection/defined_inits.c3t diff --git a/releasenotes.md b/releasenotes.md index 2fe821ac3..6318ec34e 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -93,6 +93,7 @@ - Compiler hangs on == overload if other is generic #2443 - Fix missing end of line when encountering errors in project creation. - Const enum methods are not being recognized. #2445 +- $defined returns an error when assigning a struct initializer with an incorrect type #2449 ### Stdlib changes - Add `==` to `Pair`, `Triple` and TzDateTime. Add print to `Pair` and `Triple`. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 78da403e9..674bcef76 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -2416,7 +2416,7 @@ bool sema_analyse_expr(SemaContext *context, Expr *expr); bool sema_cast_const(Expr *expr); bool sema_expr_check_discard(SemaContext *context, Expr *expr); -bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr); +bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref); bool sema_analyse_decl(SemaContext *context, Decl *decl); bool sema_analyse_method_register(SemaContext *context, Decl *method); @@ -2429,7 +2429,7 @@ bool sema_analyse_statement(SemaContext *context, Ast *statement); bool sema_expr_analyse_assign_right_side(SemaContext *context, Expr *expr, Type *left_type, Expr *right, bool is_unwrapped_var, bool is_declaration, bool *failed_ref); -bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr); +bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref); Expr **sema_expand_vasplat_exprs(SemaContext *context, Expr **exprs); bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl, Expr *struct_var, bool optional, diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 5954ae357..abf68a5d1 100755 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1690,7 +1690,7 @@ ERR: bool sema_analyse_const_enum_constant_val(SemaContext *context, Decl *decl) { Expr *value = decl->enum_constant.value; - if (!sema_analyse_inferred_expr(context, decl->type, value)) return decl_poison(decl); + if (!sema_analyse_inferred_expr(context, decl->type, value,NULL)) return decl_poison(decl); if (!expr_is_runtime_const(value)) { SEMA_ERROR(value, "Expected an constant enum value."); @@ -3612,7 +3612,7 @@ static inline bool sema_analyse_custom_attribute(SemaContext *context, ResolvedA if (!sema_resolve_type_info(context, type_infoptr(param->var.type_info), RESOLVE_TYPE_DEFAULT)) return false; Type *type = typeget(param->var.type_info); ASSERT_SPAN(decl, type); - if (!sema_analyse_inferred_expr(context, type, expr)) goto ERR; + if (!sema_analyse_inferred_expr(context, type, expr, NULL)) goto ERR; if (!cast_implicit(context, expr, type, false)) goto ERR; if (!sema_cast_const(expr)) { diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 9fb051604..24a72c975 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -51,7 +51,7 @@ static inline bool sema_expr_analyse_pointer_offset(SemaContext *context, Expr * static inline bool sema_expr_analyse_slice(SemaContext *context, Expr *expr, CheckType check); static inline bool sema_expr_analyse_access(SemaContext *context, Expr *expr, bool *missing_ref, CheckType check, bool lvalue); -static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr); +static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr, bool *no_match_ref); static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error); static inline bool sema_expr_analyse_binary(SemaContext *context, Type *infer_type, Expr *expr, bool *failed_ref); static inline bool sema_expr_resolve_ct_eval(SemaContext *context, Expr *expr); @@ -1365,7 +1365,7 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr if (!sema_analyse_expr(context, left)) return false; if (type_kind_is_any_vector(type_flatten(left->type)->type_kind)) { - return sema_analyse_inferred_expr(context, left->type, right); + return sema_analyse_inferred_expr(context, left->type, right, NULL); } return sema_analyse_expr(context, right); } @@ -1374,7 +1374,7 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr if (!sema_analyse_expr(context, right)) return false; if (type_kind_is_any_vector(type_flatten(right->type)->type_kind)) { - return sema_analyse_inferred_expr(context, right->type, left); + return sema_analyse_inferred_expr(context, right->type, left, NULL); } return sema_analyse_expr(context, left); } @@ -1386,7 +1386,7 @@ static inline bool sema_binary_analyse_with_inference(SemaContext *context, Expr { case TYPE_ENUM: case TYPE_CONST_ENUM: - return sema_analyse_inferred_expr(context, left->type, right); + return sema_analyse_inferred_expr(context, left->type, right, NULL); default: return sema_analyse_expr(context, right); } @@ -1405,7 +1405,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, { case TYPE_ENUM: case TYPE_CONST_ENUM: - return sema_analyse_inferred_expr(context, left->type, right); + return sema_analyse_inferred_expr(context, left->type, right, NULL); default: break; } @@ -1418,7 +1418,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, { case TYPE_ENUM: case TYPE_CONST_ENUM: - return sema_analyse_inferred_expr(context, right->type, left); + return sema_analyse_inferred_expr(context, right->type, left, NULL); default: break; } @@ -1428,7 +1428,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, if (!sema_analyse_expr(context, left)) return false; if (type_kind_is_any_vector(type_flatten(left->type)->type_kind)) { - return sema_analyse_inferred_expr(context, left->type, right); + return sema_analyse_inferred_expr(context, left->type, right, NULL); } return sema_analyse_expr(context, right); } @@ -1437,7 +1437,7 @@ static inline bool sema_binary_analyse_subexpr(SemaContext *context, Expr *left, if (!sema_analyse_expr(context, right)) return false; if (type_kind_is_any_vector(type_flatten(right->type)->type_kind)) { - return sema_analyse_inferred_expr(context, right->type, left); + return sema_analyse_inferred_expr(context, right->type, left, NULL); } return sema_analyse_expr(context, left); } @@ -3820,7 +3820,7 @@ static inline bool sema_expr_resolve_subscript_index(SemaContext *context, Expr if (overload) { index_type = overload->func_decl.signature.params[1]->type; - if (!sema_analyse_inferred_expr(context, index_type, index)) + if (!sema_analyse_inferred_expr(context, index_type, index, NULL)) { expr_poison(index); return false; @@ -5984,10 +5984,10 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *context, Expr *expr { if (!is_dead || context->active_scope.is_dead) { - return infer_type ? sema_analyse_inferred_expr(context, infer_type, expr) : sema_analyse_expr(context, expr); + return infer_type ? sema_analyse_inferred_expr(context, infer_type, expr, NULL) : sema_analyse_expr(context, expr); } context->active_scope.is_dead = true; - bool success = infer_type ? sema_analyse_inferred_expr(context, infer_type, expr) : sema_analyse_expr(context, expr); + bool success = infer_type ? sema_analyse_inferred_expr(context, infer_type, expr, NULL) : sema_analyse_expr(context, expr); context->active_scope.is_dead = false; return success; } @@ -6579,7 +6579,7 @@ static inline bool sema_expr_analyse_cast(SemaContext *context, Expr *expr, bool { expr->expr_kind = EXPR_COMPOUND_LITERAL; expr->expr_compound_literal = (ExprCompoundLiteral) { .initializer = inner, .type_info = type_info }; - return sema_expr_analyse_compound_literal(context, expr); + return sema_expr_analyse_compound_literal(context, expr, invalid_cast_ref); } bool success = sema_resolve_type_info(context, type_info, RESOLVE_TYPE_ALLOW_INFER); if (!sema_analyse_expr(context, inner) || !success) return false; @@ -6613,7 +6613,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ Type *base = left_flat->array.base; if (right->expr_kind == EXPR_SLICE || (compiler.build.old_slice_copy && right->expr_kind == EXPR_INITIALIZER_LIST && right->initializer_list)) { - if (!sema_analyse_inferred_expr(context, left_type, right)) return false; + if (!sema_analyse_inferred_expr(context, left_type, right, NULL)) return false; if (left_flat == type_flatten(right->type) || right->type == type_untypedlist) goto SLICE_COPY; } else @@ -6637,7 +6637,7 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ type_quoted_error_string(base)); } } - if (!sema_analyse_inferred_expr(context, base, right)) return false; + if (!sema_analyse_inferred_expr(context, base, right, NULL)) return false; } Type *right_type = right->type->canonical; if (base->canonical != right_type && (type_is_arraylike(right_type) || right_type->type_kind == TYPE_SLICE)) @@ -6719,7 +6719,7 @@ static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *e ASSERT_SPAN(left, left->resolve_status == RESOLVE_DONE); // Evaluate right side to using inference from last type. - if (!sema_analyse_inferred_expr(context, left->type, right)) return false; + if (!sema_analyse_inferred_expr(context, left->type, right, NULL)) return false; if (!expr_is_runtime_const(right)) { @@ -6926,7 +6926,7 @@ static bool sema_binary_analyse_ct_subscript_op_assign(SemaContext *context, Exp static BoolErr sema_insert_overload_in_op_assign_or_error(SemaContext *context, Expr *expr, Expr *left, Expr *right, BinaryOp operator, Type *lhs_type) { assert(type_is_user_defined(lhs_type)); - if (!sema_analyse_inferred_expr(context, lhs_type, right)) return BOOL_ERR; + if (!sema_analyse_inferred_expr(context, lhs_type, right, NULL)) return BOOL_ERR; static OperatorOverload MAP[BINARYOP_LAST + 1] = { [BINARYOP_ADD_ASSIGN] = OVERLOAD_PLUS_ASSIGN, [BINARYOP_SUB_ASSIGN] = OVERLOAD_MINUS_ASSIGN, @@ -7208,7 +7208,7 @@ BITSTRUCT_OK: } else { - if (!sema_analyse_inferred_expr(context, left->type, right)) return false; + if (!sema_analyse_inferred_expr(context, left->type, right, NULL)) return false; } // 3. Copy type & set properties. @@ -9100,7 +9100,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr, } else { - if (!sema_analyse_inferred_expr(context, infer_type, left)) return false; + if (!sema_analyse_inferred_expr(context, infer_type, left, NULL)) return false; } Type *type = left->type; @@ -9118,7 +9118,7 @@ static inline bool sema_expr_analyse_or_error(SemaContext *context, Expr *expr, EndJump active_scope_jump = context->active_scope.end_jump; // First we analyse the "else" and try to implictly cast. - if (!sema_analyse_inferred_expr(context, infer_type, right)) return false; + if (!sema_analyse_inferred_expr(context, infer_type, right, NULL)) return false; if (left->expr_kind == EXPR_OPTIONAL) { @@ -10585,10 +10585,16 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr success = false; } break; + case EXPR_COMPOUND_LITERAL: + if (!sema_expr_analyse_compound_literal(context, main_expr, &failed)) + { + if (!failed) goto FAIL; + success = false; + } + break; case EXPR_CT_ARG: case EXPR_BITACCESS: case EXPR_BITASSIGN: - case EXPR_COMPOUND_LITERAL: case EXPR_EMBED: case EXPR_GENERIC_IDENT: case EXPR_MACRO_BODY: @@ -10695,7 +10701,7 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty // Not found, so generate a new. if (!decl) { - if (!sema_analyse_inferred_expr(context, infer_type, arg_expr)) return false; + if (!sema_analyse_inferred_expr(context, infer_type, arg_expr, NULL)) return false; switch (sema_resolve_storage_type(context, arg_expr->type)) { case STORAGE_ERROR: @@ -10721,14 +10727,14 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty // An expr argument, this means we copy and evaluate. ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg), NULL), false); expr_replace(expr, copy_expr_single(arg_expr)); - return sema_analyse_inferred_expr(context, infer_type, expr); + return sema_analyse_inferred_expr(context, infer_type, expr, NULL); } case TOKEN_CT_VACONST: { // An expr argument, this means we copy and evaluate. ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg), NULL), false); arg_expr = copy_expr_single(arg_expr); - if (!sema_analyse_inferred_expr(context, infer_type, arg_expr)) return false; + if (!sema_analyse_inferred_expr(context, infer_type, arg_expr, NULL)) return false; if (!sema_cast_const(arg_expr)) { RETURN_SEMA_ERROR(arg_expr, "This argument needs to be a compile time constant."); @@ -10801,7 +10807,7 @@ static inline bool sema_expr_analyse_assignable(SemaContext *context, Expr *expr } if (!type) RETURN_SEMA_ERROR(type_expr, "Expected a type or constant typeid here."); Expr *inner = exprptr(expr->assignable_expr.expr); - if (!sema_analyse_inferred_expr(context, type, inner)) goto FAILED; + if (!sema_analyse_inferred_expr(context, type, inner, NULL)) goto FAILED; bool ok = may_cast(context, inner, type, false, true); expr_rewrite_const_bool(expr, type_bool, ok); context->call_env.in_no_eval = in_no_eval; @@ -10980,7 +10986,7 @@ static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, b return true; } -static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr) +static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr *expr, bool *no_match_ref) { TypeInfo *type_info = expr->expr_compound_literal.type_info; // We allow infering the size of arrays. @@ -10991,7 +10997,7 @@ static inline bool sema_expr_analyse_compound_literal(SemaContext *context, Expr RETURN_SEMA_ERROR(type_info, "The type here should always be written as a plain type and not an optional, please remove the '?'."); } if (!sema_resolve_type_structure(context, type)) return false; - if (!sema_expr_analyse_initializer_list(context, type, expr->expr_compound_literal.initializer)) return false; + if (!sema_expr_analyse_initializer_list(context, type, expr->expr_compound_literal.initializer, no_match_ref)) return false; expr_replace(expr, expr->expr_compound_literal.initializer); return true; } @@ -11153,7 +11159,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, case EXPR_FORCE_UNWRAP: return sema_expr_analyse_force_unwrap(context, expr); case EXPR_COMPOUND_LITERAL: - return sema_expr_analyse_compound_literal(context, expr); + return sema_expr_analyse_compound_literal(context, expr, NULL); case EXPR_RETHROW: return sema_expr_analyse_rethrow(context, expr, NULL); case EXPR_CONST: @@ -11187,7 +11193,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, return sema_expr_analyse_access(context, expr, NULL, check, false); case EXPR_INITIALIZER_LIST: case EXPR_DESIGNATED_INITIALIZER_LIST: - return sema_expr_analyse_initializer_list(context, type_untypedlist, expr); + return sema_expr_analyse_initializer_list(context, type_untypedlist, expr, NULL); case EXPR_CAST: return sema_expr_analyse_cast(context, expr, NULL); case EXPR_EXPRESSION_LIST: @@ -11229,7 +11235,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo } else { - if (!sema_analyse_inferred_expr(context, to, expr)) return false; + if (!sema_analyse_inferred_expr(context, to, expr, no_match_ref)) return false; } if (!sema_cast_rvalue(context, expr, true)) return false; if (to) to = type_no_optional(to); @@ -11761,7 +11767,7 @@ bool sema_cast_const(Expr *expr) UNREACHABLE } -bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr) +bool sema_analyse_inferred_expr(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref) { Type *original_type = to; to = type_no_optional(to); @@ -11796,13 +11802,13 @@ RETRY: InliningSpan *old_span = context->inlined_at; context->inlined_at = new_span; expr_replace(expr, expr->expr_other_context.inner); - bool success = sema_analyse_inferred_expr(context, original_type, expr); + bool success = sema_analyse_inferred_expr(context, original_type, expr, no_match_ref); context->inlined_at = old_span; return success; } case EXPR_DESIGNATED_INITIALIZER_LIST: case EXPR_INITIALIZER_LIST: - if (!sema_expr_analyse_initializer_list(context, to, expr)) return expr_poison(expr); + if (!sema_expr_analyse_initializer_list(context, to, expr, no_match_ref)) return expr_poison(expr); break; case EXPR_UNRESOLVED_IDENTIFIER: if (!sema_expr_analyse_identifier(context, to, expr)) return expr_poison(expr); @@ -11828,7 +11834,7 @@ RETRY: case EXPR_UNARY: if (to && expr->unary_expr.operator == UNARYOP_TADDR && to->canonical->type_kind == TYPE_POINTER && to->canonical != type_voidptr) { - if (!sema_analyse_inferred_expr(context, type_get_indexed_type(to), expr->unary_expr.expr)) return expr_poison(expr); + if (!sema_analyse_inferred_expr(context, type_get_indexed_type(to), expr->unary_expr.expr,NULL)) return expr_poison(expr); } FALLTHROUGH; default: diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 52993c7e4..604f50e48 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -4,14 +4,14 @@ #include "sema_internal.h" -static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer); +static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer, bool *no_match_ref); static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Type *flattened, - Expr *initializer); -static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer); + Expr *initializer, bool *no_match_ref); +static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer, bool *no_match_ref); static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Type *flattened, - Expr *initializer); + Expr *initializer, bool *no_match_ref); static inline void sema_not_enough_elements_error(SemaContext *context, Expr *initializer, int element); -static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr); +static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr, bool *no_match_ref); static void sema_create_const_initializer_from_designated_init(ConstInitializer *const_init, Expr *initializer); static Decl *sema_resolve_element_for_name(SemaContext *context, Decl **decls, DesignatorElement ***elements_ref, unsigned *index, bool is_substruct); static Type *sema_expr_analyse_designator(SemaContext *context, Type *current, Expr *expr, ArrayIndex *max_index, Decl **member_ptr); @@ -182,7 +182,7 @@ static inline void sema_not_enough_elements_error(SemaContext *context, Expr *in * Perform analysis for a plain initializer, that is one initializing all fields. * @return true if analysis succeeds. */ -static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer) +static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *context, Decl *assigned, Expr *initializer, bool *no_match_ref) { ASSERT(assigned->resolve_status == RESOLVE_DONE); Expr **elements = initializer->initializer_list; @@ -198,6 +198,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte // 2. We don't support this actually, but we used to. Maybe we will in the future. if (elements_needed == 0) { + if (no_match_ref) goto NO_MATCH; // Generate a nice error message for zero. RETURN_SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty."); } @@ -222,6 +223,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte // user pinpoint where they put the double elements. if (i >= elements_needed) { + if (no_match_ref) goto NO_MATCH; ASSERT(i < size); RETURN_SEMA_ERROR(elements[i], "Too many elements in initializer, expected only %d.", elements_needed); } @@ -245,6 +247,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte } if (i >= size) { + if (!no_match_ref) goto NO_MATCH; sema_not_enough_elements_error(context, initializer, (int)i); return false; } @@ -265,12 +268,13 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte } if (i >= size) { + if (!no_match_ref) goto NO_MATCH; sema_not_enough_elements_error(context, initializer, i); return false; } Expr *element = elements[i]; // 6. We know the required type, so resolve the expression. - if (!sema_analyse_expr_rhs(context, members[i]->type, element, true, NULL, false)) return false; + if (!sema_analyse_expr_rhs(context, members[i]->type, element, true, no_match_ref, false)) return false; if (member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER) { if (!sema_bit_assignment_check(context, element, members[i])) return false; @@ -302,7 +306,9 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte // 7. Done! return true; - +NO_MATCH:; + *no_match_ref = true; + return false; } Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Expr **exprs) @@ -316,7 +322,7 @@ Expr *sema_create_struct_from_expressions(Decl *struct_decl, SourceSpan span, Ex * @return true if analysis succeeds. */ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *context, Type *assigned, Type *flattened, - Expr *initializer) + Expr *initializer, bool *no_match_ref) { Expr **elements = initializer->initializer_list; bool inferred_len = type_len_is_inferred(flattened); @@ -338,9 +344,9 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex if (expected_members == 0 && !inferred_len) { + if (no_match_ref) goto NO_MATCH; // Generate a nice error message for zero. - SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty."); - return false; + RETURN_SEMA_ERROR(elements[0], "Too many elements in initializer, it must be empty."); } bool optional = false; @@ -353,12 +359,12 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex Expr *element = elements[i]; if (!inferred_len && i >= expected_members) { - SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members); - return false; + if (no_match_ref) goto NO_MATCH; + RETURN_SEMA_ERROR(element, "Too many elements in initializer, expected only %d.", expected_members); } if (is_vector) { - if (!sema_analyse_inferred_expr(context, inner_type, element)) return false; + if (!sema_analyse_inferred_expr(context, inner_type, element, no_match_ref)) return false; Type *element_type = element->type; Type *element_flat = type_flatten(element_type); if (element_flat->type_kind == TYPE_VECTOR @@ -367,8 +373,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex unsigned len = element_flat->array.len; if (!inferred_len && i + len > expected_members) { - SEMA_ERROR(element, "Too many elements in initializer when expanding, expected only %d.", expected_members); - return false; + RETURN_SEMA_ERROR(element, "Too many elements in initializer when expanding, expected only %d.", expected_members); } Expr *expr_two = expr_new_expr(EXPR_TWO, element); Decl *decl = decl_new_generated_var(element_type, VARDECL_LOCAL, element->span); @@ -394,19 +399,19 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex optional = optional || IS_OPTIONAL(element); continue; } - if (!cast_implicit(context, element, inner_type, false)) return false; + if (!cast_implicit_checked(context, element, inner_type, false, no_match_ref)) return false; optional = optional || IS_OPTIONAL(element); } else { - if (!sema_analyse_expr_rhs(context, inner_type, element, true, NULL, false)) return false; + if (!sema_analyse_expr_rhs(context, inner_type, element, true, no_match_ref, false)) return false; if (inner_is_inferred) { if (inferred_element) { - if (!cast_implicit(context, element, inferred_element, false)) + if (!cast_implicit_checked(context, element, inferred_element, false, no_match_ref)) { - SEMA_NOTE(elements[0], "Type inferred from here."); + if (!no_match_ref) SEMA_NOTE(elements[0], "Type inferred from here."); return false; } } @@ -422,8 +427,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex { if (!inferred_element) { - SEMA_ERROR(initializer, "Zero sized elements are not allowed when inferring size."); - return false; + if (no_match_ref) goto NO_MATCH; + RETURN_SEMA_ERROR(initializer, "Zero sized elements are not allowed when inferring size."); } inner_type = inferred_element; } @@ -441,8 +446,8 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex if (!inferred_len && expected_members > count) { - SEMA_ERROR(elements[count - 1], "Too few elements in initializer, %d elements are needed.", expected_members); - return false; + if (no_match_ref) goto NO_MATCH; + RETURN_SEMA_ERROR(elements[count - 1], "Too few elements in initializer, %d elements are needed.", expected_members); } initializer->resolve_status = RESOLVE_DONE; @@ -464,9 +469,12 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex // 7. Done! return true; +NO_MATCH:; + *no_match_ref = true; + return false; } -static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer) +static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, Expr *initializer, bool *no_match_ref) { Expr **init_list = initializer->initializer_list; FOREACH(Expr *, element, init_list) @@ -474,6 +482,11 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E if (!sema_analyse_expr(context, element)) return false; if (!sema_cast_const(element)) { + if (no_match_ref) + { + *no_match_ref = true; + return false; + } RETURN_SEMA_ERROR(element, "An untyped list can only have " "constant elements, you can try " "to type the list by prefixing the type and possibly enclosing it in parentheses, " @@ -488,7 +501,7 @@ static inline bool sema_expr_analyse_untyped_initializer(SemaContext *context, E } static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type *assigned, Type *flattened, - Expr *initializer) + Expr *initializer, bool *no_match_ref) { Expr **init_expressions = initializer->designated_init_list; Type *original = flattened->canonical; @@ -513,7 +526,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type bitmember_count_without_value += 1; } if (!value) RETURN_SEMA_ERROR(expr, "This initializer needs a value."); - if (!sema_analyse_expr_rhs(context, result, value, true, NULL, false)) return false; + if (!sema_analyse_expr_rhs(context, result, value, true, no_match_ref, false)) return false; if (is_bitmember) { if (!sema_bit_assignment_check(context, value, member)) return false; @@ -525,7 +538,8 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type inner_type = type_no_optional(value->type); } } - if (bitmember_count_without_value != 0 && bitmember_count_without_value != vec_size(init_expressions)) { + if (bitmember_count_without_value != 0 && bitmember_count_without_value != vec_size(init_expressions)) + { RETURN_SEMA_ERROR(initializer, "Mixing the omission of initializers is not permitted."); } Type *type; @@ -549,7 +563,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type } -static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr) +static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *assigned_type, Type *flattened, Expr *expr, bool *no_match_ref) { // Note at this point this we either have // EXPR_DESIGNATED_INITIALIZER_LIST @@ -559,13 +573,13 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass // 1. Designated initializer is separately evaluated. if (expr->expr_kind == EXPR_DESIGNATED_INITIALIZER_LIST) { - return sema_expr_analyse_designated_initializer(context, assigned_type, flattened, expr); + return sema_expr_analyse_designated_initializer(context, assigned_type, flattened, expr,NULL); } if (expr->expr_kind == EXPR_CONST) { ASSERT(expr->const_expr.const_kind == CONST_INITIALIZER); - return cast_implicit(context, expr, assigned_type, false); + return cast_implicit_checked(context, expr, assigned_type, false, no_match_ref); } ASSERT(expr->expr_kind == EXPR_INITIALIZER_LIST); @@ -583,8 +597,8 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass { if (type_len_is_inferred(assigned_type)) { - SEMA_ERROR(expr, "Zero length arrays / vectors are not permitted."); - return false; + if (no_match_ref) goto NO_MATCH; + RETURN_SEMA_ERROR(expr, "Zero length arrays / vectors are not permitted."); } if (flattened == type_untypedlist) { @@ -598,7 +612,7 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass // 4. We might have a complist, because were analyzing $foo = { ... } or similar. if (assigned_type == type_untypedlist) { - return sema_expr_analyse_untyped_initializer(context, expr); + return sema_expr_analyse_untyped_initializer(context, expr, no_match_ref); } // 5. If not, then we see if we have an array. @@ -609,11 +623,14 @@ static inline bool sema_expr_analyse_initializer(SemaContext *context, Type *ass flattened->type_kind == TYPE_SLICE || flattened->type_kind == TYPE_VECTOR) { - return sema_expr_analyse_array_plain_initializer(context, assigned_type, flattened, expr); + return sema_expr_analyse_array_plain_initializer(context, assigned_type, flattened, expr, no_match_ref); } expr->type = assigned_type; - return sema_expr_analyse_struct_plain_initializer(context, flattened->decl, expr); + return sema_expr_analyse_struct_plain_initializer(context, flattened->decl, expr, no_match_ref); +NO_MATCH:; + *no_match_ref = true; + return false; } /** @@ -773,7 +790,7 @@ ConstInitializer *sema_merge_bitstruct_const_initializers(ConstInitializer *lhs, return lhs; } -bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr) +bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *expr, bool *no_match_ref) { if (!to) to = type_untypedlist; @@ -801,7 +818,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex case TYPE_INFERRED_ARRAY: case TYPE_INFERRED_VECTOR: case TYPE_VECTOR: - return sema_expr_analyse_initializer(context, to, flattened, expr); + return sema_expr_analyse_initializer(context, to, flattened, expr, no_match_ref); case TYPE_SLICE: { if (is_zero_init) @@ -811,7 +828,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex } // Resolve this as an inferred array. Type *type = type_get_inferred_array(flattened->array.base); - if (!sema_expr_analyse_initializer(context, type, type, expr)) return false; + if (!sema_expr_analyse_initializer(context, type, type, expr, no_match_ref)) return false; if (expr_is_const_initializer(expr)) { ConstInitializer *init = expr->const_expr.initializer; @@ -823,6 +840,11 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex expr->resolve_status = RESOLVE_DONE; expr_insert_addr(expr); if (!sema_analyse_expr(context, expr)) return false; + if (no_match_ref) + { + if (!cast_explicit_silent(context, expr, to)) goto NO_MATCH; + return true; + } return cast_explicit(context, expr, to); } case TYPE_POINTER: @@ -832,6 +854,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex expr_rewrite_to_const_zero(expr, to); return true; } + if (no_match_ref) goto NO_MATCH; RETURN_SEMA_ERROR(expr, "Pointers cannot be initialized using an initializer list, instead you need to take the address of an array."); case TYPE_VOID: case TYPE_POISONED: @@ -840,6 +863,7 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex case TYPE_OPTIONAL: case TYPE_TYPEINFO: case TYPE_MEMBER: + if (no_match_ref) goto NO_MATCH; RETURN_SEMA_ERROR(expr, "You cannot use %s with an initializer list.", type_quoted_error_string(to)); default: if (is_zero_init) @@ -850,7 +874,11 @@ bool sema_expr_analyse_initializer_list(SemaContext *context, Type *to, Expr *ex } break; } + if (no_match_ref) goto NO_MATCH; RETURN_SEMA_ERROR(expr, "You cannot use %s with a non-empty initializer list.", type_quoted_error_string(to)); +NO_MATCH: + *no_match_ref = true; + return false; } void const_init_rewrite_to_value(ConstInitializer *const_init, Expr *value) diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index dbf2120b6..eece104fd 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -1494,7 +1494,7 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen if (variable_type_info) { - if (!sema_analyse_inferred_expr(context, inferred_type, enumerator)) return SCOPE_POP_ERROR(); + if (!sema_analyse_inferred_expr(context, inferred_type, enumerator,NULL)) return SCOPE_POP_ERROR(); } else { diff --git a/test/test_suite/compile_time_introspection/defined_inits.c3t b/test/test_suite/compile_time_introspection/defined_inits.c3t new file mode 100644 index 000000000..77aa573ab --- /dev/null +++ b/test/test_suite/compile_time_introspection/defined_inits.c3t @@ -0,0 +1,23 @@ +// #target: macos-x64 +module test; +struct Test +{ + int a; + String b; +} +fn int main() +{ + bool a = $defined(Test a = {"hello"}); + bool b = $defined((Test){"hello"}); + return 0; +} +/* #expect: test.ll + +define i32 @main() #0 { +entry: + %a = alloca i8, align 1 + %b = alloca i8, align 1 + store i8 0, ptr %a, align 1 + store i8 0, ptr %b, align 1 + ret i32 0 +}