mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-17 08:34:08 +00:00
Add struct #no_copy
This commit is contained in:
@@ -119,6 +119,7 @@ Type_Info_Struct :: struct {
|
||||
tags: []string,
|
||||
is_packed: bool,
|
||||
is_raw_union: bool,
|
||||
is_no_copy: bool,
|
||||
custom_align: bool,
|
||||
|
||||
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
|
||||
|
||||
@@ -131,6 +131,14 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
|
||||
if (d != nullptr) {
|
||||
d->init_expr = o->expr;
|
||||
}
|
||||
|
||||
if (o->type && is_type_no_copy(o->type)) {
|
||||
begin_error_block();
|
||||
if (check_no_copy_assignment(*o, str_lit("initialization"))) {
|
||||
error_line("\tInitialization of a #no_copy type must be either implicitly zero, a constant literal, or from a return value a call expression");
|
||||
}
|
||||
end_error_block();
|
||||
}
|
||||
}
|
||||
if (rhs_count > 0 && lhs_count != rhs_count) {
|
||||
error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
|
||||
|
||||
@@ -5043,6 +5043,21 @@ gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lh
|
||||
return tuple_count;
|
||||
}
|
||||
|
||||
gb_internal bool check_no_copy_assignment(Operand const &o, String const &context) {
|
||||
if (o.type && is_type_no_copy(o.type)) {
|
||||
Ast *expr = unparen_expr(o.expr);
|
||||
if (expr && o.mode != Addressing_Constant) {
|
||||
if (expr->kind == Ast_CallExpr) {
|
||||
// Okay
|
||||
} else {
|
||||
error(o.expr, "Invalid use a #no_copy value in %.*s", LIT(context));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand> const &lhs, Array<Operand> *operands, Slice<Ast *> const &rhs) {
|
||||
bool optional_ok = false;
|
||||
@@ -5114,6 +5129,7 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand>
|
||||
for (Entity *e : tuple->variables) {
|
||||
o.type = e->type;
|
||||
array_add(operands, o);
|
||||
check_no_copy_assignment(o, str_lit("assignment"));
|
||||
}
|
||||
|
||||
tuple_index += tuple->variables.count;
|
||||
@@ -5952,6 +5968,10 @@ gb_internal CallArgumentData check_call_arguments(CheckerContext *c, Operand *op
|
||||
}
|
||||
}
|
||||
|
||||
for (Operand const &o : operands) {
|
||||
check_no_copy_assignment(o, str_lit("call expression"));
|
||||
}
|
||||
|
||||
if (operand->mode == Addressing_ProcGroup) {
|
||||
check_entity_decl(c, operand->proc_group, nullptr, nullptr);
|
||||
|
||||
|
||||
@@ -326,7 +326,6 @@ gb_internal bool check_is_terminating(Ast *node, String const &label) {
|
||||
|
||||
|
||||
|
||||
|
||||
gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
|
||||
if (rhs->mode == Addressing_Invalid) {
|
||||
return nullptr;
|
||||
@@ -339,6 +338,8 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
|
||||
Ast *node = unparen_expr(lhs->expr);
|
||||
|
||||
check_no_copy_assignment(*rhs, str_lit("assignment"));
|
||||
|
||||
// NOTE(bill): Ignore assignments to '_'
|
||||
if (is_blank_ident(node)) {
|
||||
check_assignment(ctx, rhs, nullptr, str_lit("assignment to '_' identifier"));
|
||||
@@ -400,6 +401,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
|
||||
}
|
||||
|
||||
Type *assignment_type = lhs->type;
|
||||
|
||||
switch (lhs->mode) {
|
||||
case Addressing_Invalid:
|
||||
return nullptr;
|
||||
|
||||
@@ -609,8 +609,9 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
context = str_lit("struct #raw_union");
|
||||
}
|
||||
|
||||
struct_type->Struct.scope = ctx->scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.scope = ctx->scope;
|
||||
struct_type->Struct.is_packed = st->is_packed;
|
||||
struct_type->Struct.is_no_copy = st->is_no_copy;
|
||||
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
|
||||
ctx, st->polymorphic_params,
|
||||
&struct_type->Struct.is_polymorphic,
|
||||
|
||||
@@ -691,32 +691,34 @@ gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup
|
||||
case Type_Struct: {
|
||||
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr);
|
||||
|
||||
LLVMValueRef vals[12] = {};
|
||||
LLVMValueRef vals[13] = {};
|
||||
|
||||
|
||||
{
|
||||
lbValue is_packed = lb_const_bool(m, t_bool, t->Struct.is_packed);
|
||||
lbValue is_raw_union = lb_const_bool(m, t_bool, t->Struct.is_raw_union);
|
||||
lbValue is_no_copy = lb_const_bool(m, t_bool, t->Struct.is_no_copy);
|
||||
lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0);
|
||||
vals[5] = is_packed.value;
|
||||
vals[6] = is_raw_union.value;
|
||||
vals[7] = is_custom_align.value;
|
||||
vals[7] = is_no_copy.value;
|
||||
vals[8] = is_custom_align.value;
|
||||
if (is_type_comparable(t) && !is_type_simple_compare(t)) {
|
||||
vals[8] = lb_equal_proc_for_type(m, t).value;
|
||||
vals[9] = lb_equal_proc_for_type(m, t).value;
|
||||
}
|
||||
|
||||
|
||||
if (t->Struct.soa_kind != StructSoa_None) {
|
||||
lbValue kind = lb_emit_struct_ep(p, tag, 9);
|
||||
lbValue kind = lb_emit_struct_ep(p, tag, 10);
|
||||
Type *kind_type = type_deref(kind.type);
|
||||
|
||||
lbValue soa_kind = lb_const_value(m, kind_type, exact_value_i64(t->Struct.soa_kind));
|
||||
lbValue soa_type = lb_type_info(m, t->Struct.soa_elem);
|
||||
lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count);
|
||||
|
||||
vals[9] = soa_kind.value;
|
||||
vals[10] = soa_type.value;
|
||||
vals[11] = soa_len.value;
|
||||
vals[10] = soa_kind.value;
|
||||
vals[11] = soa_type.value;
|
||||
vals[12] = soa_len.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1047,7 +1047,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,
|
||||
Ast *polymorphic_params, bool is_packed, bool is_raw_union, bool is_no_copy,
|
||||
Ast *align,
|
||||
Token where_token, Array<Ast *> const &where_clauses) {
|
||||
Ast *result = alloc_ast_node(f, Ast_StructType);
|
||||
@@ -1057,6 +1057,7 @@ gb_internal Ast *ast_struct_type(AstFile *f, Token token, Slice<Ast *> fields, i
|
||||
result->StructType.polymorphic_params = polymorphic_params;
|
||||
result->StructType.is_packed = is_packed;
|
||||
result->StructType.is_raw_union = is_raw_union;
|
||||
result->StructType.is_no_copy = is_no_copy;
|
||||
result->StructType.align = align;
|
||||
result->StructType.where_token = where_token;
|
||||
result->StructType.where_clauses = slice_from_array(where_clauses);
|
||||
@@ -2392,6 +2393,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
Ast *polymorphic_params = nullptr;
|
||||
bool is_packed = false;
|
||||
bool is_raw_union = false;
|
||||
bool no_copy = false;
|
||||
Ast *align = nullptr;
|
||||
|
||||
if (allow_token(f, Token_OpenParen)) {
|
||||
@@ -2427,6 +2429,11 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
is_raw_union = true;
|
||||
} else if (tag.string == "no_copy") {
|
||||
if (is_packed) {
|
||||
syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
no_copy = true;
|
||||
} else {
|
||||
syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string));
|
||||
}
|
||||
@@ -2465,7 +2472,7 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
decls = fields->FieldList.list;
|
||||
}
|
||||
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, align, where_token, where_clauses);
|
||||
return ast_struct_type(f, token, decls, name_count, polymorphic_params, is_packed, is_raw_union, no_copy, align, where_token, where_clauses);
|
||||
} break;
|
||||
|
||||
case Token_union: {
|
||||
|
||||
@@ -693,6 +693,7 @@ AST_KIND(_TypeBegin, "", bool) \
|
||||
Slice<Ast *> where_clauses; \
|
||||
bool is_packed; \
|
||||
bool is_raw_union; \
|
||||
bool is_no_copy; \
|
||||
}) \
|
||||
AST_KIND(UnionType, "union type", struct { \
|
||||
Scope *scope; \
|
||||
|
||||
@@ -149,6 +149,7 @@ struct TypeStruct {
|
||||
bool are_offsets_being_processed : 1;
|
||||
bool is_packed : 1;
|
||||
bool is_raw_union : 1;
|
||||
bool is_no_copy : 1;
|
||||
bool is_poly_specialized : 1;
|
||||
};
|
||||
|
||||
@@ -1670,6 +1671,10 @@ gb_internal bool is_type_raw_union(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Struct && t->Struct.is_raw_union);
|
||||
}
|
||||
gb_internal bool is_type_no_copy(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Struct && t->Struct.is_no_copy);
|
||||
}
|
||||
gb_internal bool is_type_enum(Type *t) {
|
||||
t = base_type(t);
|
||||
return (t->kind == Type_Enum);
|
||||
@@ -2655,6 +2660,7 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
|
||||
|
||||
case Type_Struct:
|
||||
if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
|
||||
x->Struct.is_no_copy == y->Struct.is_no_copy &&
|
||||
x->Struct.fields.count == y->Struct.fields.count &&
|
||||
x->Struct.is_packed == y->Struct.is_packed &&
|
||||
x->Struct.custom_align == y->Struct.custom_align &&
|
||||
@@ -4207,6 +4213,7 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
|
||||
str = gb_string_appendc(str, "struct");
|
||||
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_no_copy) str = gb_string_appendc(str, " #no_copy");
|
||||
if (type->Struct.custom_align != 0) str = gb_string_append_fmt(str, " #align %d", cast(int)type->Struct.custom_align);
|
||||
str = gb_string_appendc(str, " {");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user