aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorFaker-09 <shrybman@teksavvy.com>2026-01-29 11:35:24 -0500
committerGitHub <noreply@github.com>2026-01-29 11:35:24 -0500
commit30ef01ee8d1175dc5a974d8bee62b7ea00651941 (patch)
treecddb56cfe63f3752b8b7a8c314d9cc652f22ec28 /src
parentf6322b4b31fb0a5cc343d4bae31ebc09639e3403 (diff)
parent70059b0fba3099d0d67232ed89c268710f435a36 (diff)
Merge branch 'odin-lang:master' into vet_flags
Diffstat (limited to 'src')
-rw-r--r--src/check_expr.cpp12
-rw-r--r--src/check_stmt.cpp4
-rw-r--r--src/check_type.cpp15
-rw-r--r--src/llvm_backend_stmt.cpp3
-rw-r--r--src/parser.cpp13
-rw-r--r--src/parser.hpp1
-rw-r--r--src/types.cpp36
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, " {");