diff options
| author | Faker-09 <shrybman@teksavvy.com> | 2026-01-29 11:35:24 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-29 11:35:24 -0500 |
| commit | 30ef01ee8d1175dc5a974d8bee62b7ea00651941 (patch) | |
| tree | cddb56cfe63f3752b8b7a8c314d9cc652f22ec28 /src | |
| parent | f6322b4b31fb0a5cc343d4bae31ebc09639e3403 (diff) | |
| parent | 70059b0fba3099d0d67232ed89c268710f435a36 (diff) | |
Merge branch 'odin-lang:master' into vet_flags
Diffstat (limited to 'src')
| -rw-r--r-- | src/check_expr.cpp | 12 | ||||
| -rw-r--r-- | src/check_stmt.cpp | 4 | ||||
| -rw-r--r-- | src/check_type.cpp | 15 | ||||
| -rw-r--r-- | src/llvm_backend_stmt.cpp | 3 | ||||
| -rw-r--r-- | src/parser.cpp | 13 | ||||
| -rw-r--r-- | src/parser.hpp | 1 | ||||
| -rw-r--r-- | src/types.cpp | 36 |
7 files changed, 73 insertions, 11 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 46455aacf..1c09ad908 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -4704,12 +4704,14 @@ gb_internal void convert_to_typed(CheckerContext *c, Operand *operand, Type *tar switch (t->kind) { case Type_Basic: if (operand->mode == Addressing_Constant) { - check_is_expressible(c, operand, t); + check_is_expressible(c, operand, target_type); if (operand->mode == Addressing_Invalid) { return; } update_untyped_expr_value(c, operand->expr, operand->value); - } else { + } + + { switch (operand->type->Basic.kind) { case Basic_UntypedBool: if (!is_type_boolean(target_type)) { @@ -12692,8 +12694,10 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan str = write_expr_to_string(str, st->polymorphic_params, shorthand); str = gb_string_appendc(str, ") "); } - if (st->is_packed) str = gb_string_appendc(str, "#packed "); - if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union "); + if (st->is_packed) str = gb_string_appendc(str, "#packed "); + if (st->is_raw_union) str = gb_string_appendc(str, "#raw_union "); + if (st->is_all_or_none) str = gb_string_appendc(str, "#all_or_none "); + if (st->is_simple) str = gb_string_appendc(str, "#simple "); if (st->align) { str = gb_string_appendc(str, "#align "); str = write_expr_to_string(str, st->align, shorthand); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 835f0162a..2dc621a84 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1027,7 +1027,9 @@ gb_internal void check_unroll_range_stmt(CheckerContext *ctx, Ast *node, u32 mod error(operand.expr, "Cannot iterate over '%s' of type '%s' in an '#unroll for' statement", s, t); gb_string_free(t); gb_string_free(s); - } else if (operand.mode != Addressing_Constant && unroll_count <= 0) { + } else if (operand.mode != Addressing_Constant && ( + unroll_count <= 0 && + compare_exact_values(Token_CmpEq, inline_for_depth, exact_value_i64(0)))) { error(operand.expr, "An '#unroll for' expression must be known at compile time"); } } diff --git a/src/check_type.cpp b/src/check_type.cpp index 4b8f7b6ac..41c5f48d1 100644 --- a/src/check_type.cpp +++ b/src/check_type.cpp @@ -679,6 +679,21 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast * gb_unused(where_clause_ok); } check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context); + + if (st->is_simple) { + bool success = true; + for (Entity *f : struct_type->Struct.fields) { + if (!is_type_nearly_simple_compare(f->type)) { + gbString s = type_to_string(f->type); + error(f->token, "'struct #simple' requires all fields to be at least 'nearly simple compare', got %s", s); + gb_string_free(s); + } + } + if (success) { + struct_type->Struct.is_simple = true; + } + } + wait_signal_set(&struct_type->Struct.fields_wait_signal); } diff --git a/src/llvm_backend_stmt.cpp b/src/llvm_backend_stmt.cpp index b3b5f4251..81755af2d 100644 --- a/src/llvm_backend_stmt.cpp +++ b/src/llvm_backend_stmt.cpp @@ -1434,12 +1434,13 @@ gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt * if (unroll_count_ev.kind == ExactValue_Invalid) { - GB_ASSERT(expr->tav.mode == Addressing_Constant); Type *t = base_type(expr->tav.type); switch (t->kind) { case Type_Basic: + GB_ASSERT(expr->tav.mode == Addressing_Constant); + GB_ASSERT(is_type_string(t)); { ExactValue value = expr->tav.value; diff --git a/src/parser.cpp b/src/parser.cpp index 1f08eaec1..c14055275 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1230,7 +1230,7 @@ gb_internal Ast *ast_dynamic_array_type(AstFile *f, Token token, Ast *elem) { } gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, isize field_count, - Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none, + Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_all_or_none, bool is_simple, Ast *align, Ast *min_field_align, Ast *max_field_align, Token where_token, Array<Ast *> const &where_clauses) { Ast *result = alloc_ast_node(f, Ast_StructType); @@ -1241,6 +1241,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i result->StructType.is_packed = is_packed; result->StructType.is_raw_union = is_raw_union; result->StructType.is_all_or_none = is_all_or_none; + result->StructType.is_simple = is_simple; result->StructType.align = align; result->StructType.min_field_align = min_field_align; result->StructType.max_field_align = max_field_align; @@ -2788,6 +2789,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { bool is_packed = false; bool is_all_or_none = false; bool is_raw_union = false; + bool is_simple = false; Ast *align = nullptr; Ast *min_field_align = nullptr; Ast *max_field_align = nullptr; @@ -2869,11 +2871,16 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { error_line("\tSuggestion: #max_field_align(%s)", s); gb_string_free(s); } - }else if (tag.string == "raw_union") { + } else if (tag.string == "raw_union") { if (is_raw_union) { syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); } is_raw_union = true; + } else if (tag.string == "simple") { + if (is_simple) { + syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string)); + } + is_simple = true; } else { syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string)); } @@ -2919,7 +2926,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) { parser_check_polymorphic_record_parameters(f, polymorphic_params); return ast_struct_type(f, token, decls, name_count, - polymorphic_params, is_packed, is_raw_union, is_all_or_none, + polymorphic_params, is_packed, is_raw_union, is_all_or_none, is_simple, align, min_field_align, max_field_align, where_token, where_clauses); } break; diff --git a/src/parser.hpp b/src/parser.hpp index 011330438..39f56ffae 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -780,6 +780,7 @@ AST_KIND(_TypeBegin, "", bool) \ bool is_raw_union; \ bool is_no_copy; \ bool is_all_or_none; \ + bool is_simple; \ }) \ AST_KIND(UnionType, "union type", struct { \ Scope *scope; \ diff --git a/src/types.cpp b/src/types.cpp index 911cd4448..a7f2bfda2 100644 --- a/src/types.cpp +++ b/src/types.cpp @@ -163,6 +163,7 @@ struct TypeStruct { bool is_packed : 1; bool is_raw_union : 1; bool is_all_or_none : 1; + bool is_simple : 1; bool is_poly_specialized : 1; std::atomic<bool> are_offsets_being_processed; @@ -2701,12 +2702,16 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_SoaPointer: case Type_Proc: case Type_BitSet: + case Type_BitField: return true; case Type_Matrix: return is_type_simple_compare(t->Matrix.elem); case Type_Struct: + if (t->Struct.is_simple) { + return true; + } for_array(i, t->Struct.fields) { Entity *f = t->Struct.fields[i]; if (!is_type_simple_compare(f->type)) { @@ -2728,6 +2733,16 @@ gb_internal bool is_type_simple_compare(Type *t) { case Type_SimdVector: return is_type_simple_compare(t->SimdVector.elem); + case Type_Tuple: + if (t->Tuple.variables.count == 1) { + return is_type_simple_compare(t->Tuple.variables[0]->type); + } + break; + + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + return false; } return false; @@ -2757,12 +2772,16 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) { case Type_SoaPointer: case Type_Proc: case Type_BitSet: + case Type_BitField: return true; case Type_Matrix: return is_type_nearly_simple_compare(t->Matrix.elem); case Type_Struct: + if (t->Struct.is_simple) { + return true; + } for_array(i, t->Struct.fields) { Entity *f = t->Struct.fields[i]; if (!is_type_nearly_simple_compare(f->type)) { @@ -2784,6 +2803,17 @@ gb_internal bool is_type_nearly_simple_compare(Type *t) { case Type_SimdVector: return is_type_nearly_simple_compare(t->SimdVector.elem); + case Type_Tuple: + if (t->Tuple.variables.count == 1) { + return is_type_nearly_simple_compare(t->Tuple.variables[0]->type); + } + break; + + case Type_Slice: + case Type_DynamicArray: + case Type_Map: + return false; + } return false; @@ -5099,9 +5129,11 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha str = gb_string_appendc(str, ")"); } - if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed"); - if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); + if (type->Struct.is_packed) str = gb_string_appendc(str, " #packed"); + if (type->Struct.is_raw_union) str = gb_string_appendc(str, " #raw_union"); if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align); + if (type->Struct.is_all_or_none) str = gb_string_appendc(str, " #all_or_none"); + if (type->Struct.is_simple) str = gb_string_appendc(str, " #simple"); str = gb_string_appendc(str, " {"); |