aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2023-04-15 15:36:21 +0100
committergingerBill <bill@gingerbill.org>2023-04-15 15:37:32 +0100
commit5da76ae34bac2f54b1bda5528cf49c0551e88bba (patch)
tree78a6189f351ceb8dd070c2e453c4b0462d532235 /src
parentb7b5043aea792839226baf9e6d0ca54b73dac9a5 (diff)
Add `struct #no_copy`
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.cpp8
-rw-r--r--src/check_expr.cpp20
-rw-r--r--src/check_stmt.cpp4
-rw-r--r--src/check_type.cpp5
-rw-r--r--src/llvm_backend_type.cpp16
-rw-r--r--src/parser.cpp11
-rw-r--r--src/parser.hpp1
-rw-r--r--src/types.cpp7
8 files changed, 60 insertions, 12 deletions
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 5c25dd6a3..5a8080f96 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -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);
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index f27675301..e55765ff8 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -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);
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index 4e6623fc1..388a64e00 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -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;
diff --git a/src/check_type.cpp b/src/check_type.cpp
index 7444f88be..b687e838e 100644
--- a/src/check_type.cpp
+++ b/src/check_type.cpp
@@ -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,
diff --git a/src/llvm_backend_type.cpp b/src/llvm_backend_type.cpp
index e8d286fda..3af10112f 100644
--- a/src/llvm_backend_type.cpp
+++ b/src/llvm_backend_type.cpp
@@ -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;
}
}
diff --git a/src/parser.cpp b/src/parser.cpp
index 50a9ba766..790e67db6 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -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: {
diff --git a/src/parser.hpp b/src/parser.hpp
index 5e1878cf2..5302fd274 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -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; \
diff --git a/src/types.cpp b/src/types.cpp
index 5addb5b7b..889269564 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -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, " {");