Add struct #no_copy

This commit is contained in:
gingerBill
2023-04-15 15:36:21 +01:00
parent b7b5043aea
commit 5da76ae34b
9 changed files with 61 additions and 12 deletions

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;
}
}

View File

@@ -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: {

View File

@@ -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; \

View File

@@ -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, " {");