Browse Source

Add `struct #no_copy`

gingerBill 2 years ago
parent
commit
5da76ae34b
9 changed files with 61 additions and 12 deletions
  1. 1 0
      core/runtime/core.odin
  2. 8 0
      src/check_decl.cpp
  3. 20 0
      src/check_expr.cpp
  4. 3 1
      src/check_stmt.cpp
  5. 3 2
      src/check_type.cpp
  6. 9 7
      src/llvm_backend_type.cpp
  7. 9 2
      src/parser.cpp
  8. 1 0
      src/parser.hpp
  9. 7 0
      src/types.cpp

+ 1 - 0
core/runtime/core.odin

@@ -119,6 +119,7 @@ Type_Info_Struct :: struct {
 	tags:         []string,
 	tags:         []string,
 	is_packed:    bool,
 	is_packed:    bool,
 	is_raw_union: bool,
 	is_raw_union: bool,
+	is_no_copy:   bool,
 	custom_align: bool,
 	custom_align: bool,
 
 
 	equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
 	equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set

+ 8 - 0
src/check_decl.cpp

@@ -131,6 +131,14 @@ gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize l
 		if (d != nullptr) {
 		if (d != nullptr) {
 			d->init_expr = o->expr;
 			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) {
 	if (rhs_count > 0 && lhs_count != rhs_count) {
 		error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);
 		error(lhs[0]->token, "Assignment count mismatch '%td' = '%td'", lhs_count, rhs_count);

+ 20 - 0
src/check_expr.cpp

@@ -5043,6 +5043,21 @@ gb_internal isize add_dependencies_from_unpacking(CheckerContext *c, Entity **lh
 	return tuple_count;
 	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) {
 gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand> const &lhs, Array<Operand> *operands, Slice<Ast *> const &rhs) {
 	bool optional_ok = false;
 	bool optional_ok = false;
@@ -5114,6 +5129,7 @@ gb_internal bool check_assignment_arguments(CheckerContext *ctx, Array<Operand>
 			for (Entity *e : tuple->variables) {
 			for (Entity *e : tuple->variables) {
 				o.type = e->type;
 				o.type = e->type;
 				array_add(operands, o);
 				array_add(operands, o);
+				check_no_copy_assignment(o, str_lit("assignment"));
 			}
 			}
 
 
 			tuple_index += tuple->variables.count;
 			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) {
 	if (operand->mode == Addressing_ProcGroup) {
 		check_entity_decl(c, operand->proc_group, nullptr, nullptr);
 		check_entity_decl(c, operand->proc_group, nullptr, nullptr);
 
 

+ 3 - 1
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) {
 gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, Operand *rhs) {
 	if (rhs->mode == Addressing_Invalid) {
 	if (rhs->mode == Addressing_Invalid) {
 		return nullptr;
 		return nullptr;
@@ -339,6 +338,8 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O
 
 
 	Ast *node = unparen_expr(lhs->expr);
 	Ast *node = unparen_expr(lhs->expr);
 
 
+	check_no_copy_assignment(*rhs, str_lit("assignment"));
+
 	// NOTE(bill): Ignore assignments to '_'
 	// NOTE(bill): Ignore assignments to '_'
 	if (is_blank_ident(node)) {
 	if (is_blank_ident(node)) {
 		check_assignment(ctx, rhs, nullptr, str_lit("assignment to '_' identifier"));
 		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;
 	Type *assignment_type = lhs->type;
+
 	switch (lhs->mode) {
 	switch (lhs->mode) {
 	case Addressing_Invalid:
 	case Addressing_Invalid:
 		return nullptr;
 		return nullptr;

+ 3 - 2
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");
 		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(
 	struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
 		ctx, st->polymorphic_params,
 		ctx, st->polymorphic_params,
 		&struct_type->Struct.is_polymorphic,
 		&struct_type->Struct.is_polymorphic,

+ 9 - 7
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: {
 		case Type_Struct: {
 			tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_struct_ptr);
 			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_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_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);
 				lbValue is_custom_align = lb_const_bool(m, t_bool, t->Struct.custom_align != 0);
 				vals[5] = is_packed.value;
 				vals[5] = is_packed.value;
 				vals[6] = is_raw_union.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)) {
 				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) {
 				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);
 					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_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_type = lb_type_info(m, t->Struct.soa_elem);
 					lbValue soa_len = lb_const_int(m, t_int, t->Struct.soa_count);
 					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;
 				}
 				}
 			}
 			}
 			
 			

+ 9 - 2
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,
 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,
                      Ast *align,
                      Token where_token, Array<Ast *> const &where_clauses) {
                      Token where_token, Array<Ast *> const &where_clauses) {
 	Ast *result = alloc_ast_node(f, Ast_StructType);
 	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.polymorphic_params = polymorphic_params;
 	result->StructType.is_packed          = is_packed;
 	result->StructType.is_packed          = is_packed;
 	result->StructType.is_raw_union       = is_raw_union;
 	result->StructType.is_raw_union       = is_raw_union;
+	result->StructType.is_no_copy         = is_no_copy;
 	result->StructType.align              = align;
 	result->StructType.align              = align;
 	result->StructType.where_token        = where_token;
 	result->StructType.where_token        = where_token;
 	result->StructType.where_clauses      = slice_from_array(where_clauses);
 	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;
 		Ast *polymorphic_params = nullptr;
 		bool is_packed          = false;
 		bool is_packed          = false;
 		bool is_raw_union       = false;
 		bool is_raw_union       = false;
+		bool no_copy            = false;
 		Ast *align              = nullptr;
 		Ast *align              = nullptr;
 
 
 		if (allow_token(f, Token_OpenParen)) {
 		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));
 					syntax_error(tag, "Duplicate struct tag '#%.*s'", LIT(tag.string));
 				}
 				}
 				is_raw_union = true;
 				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 {
 			} else {
 				syntax_error(tag, "Invalid struct tag '#%.*s'", LIT(tag.string));
 				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;
 			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;
 	} break;
 
 
 	case Token_union: {
 	case Token_union: {

+ 1 - 0
src/parser.hpp

@@ -693,6 +693,7 @@ AST_KIND(_TypeBegin, "", bool) \
 		Slice<Ast *> where_clauses; \
 		Slice<Ast *> where_clauses; \
 		bool is_packed;             \
 		bool is_packed;             \
 		bool is_raw_union;          \
 		bool is_raw_union;          \
+		bool is_no_copy;            \
 	}) \
 	}) \
 	AST_KIND(UnionType, "union type", struct { \
 	AST_KIND(UnionType, "union type", struct { \
 		Scope *scope; \
 		Scope *scope; \

+ 7 - 0
src/types.cpp

@@ -149,6 +149,7 @@ struct TypeStruct {
 	bool            are_offsets_being_processed : 1;
 	bool            are_offsets_being_processed : 1;
 	bool            is_packed                   : 1;
 	bool            is_packed                   : 1;
 	bool            is_raw_union                : 1;
 	bool            is_raw_union                : 1;
+	bool            is_no_copy                  : 1;
 	bool            is_poly_specialized         : 1;
 	bool            is_poly_specialized         : 1;
 };
 };
 
 
@@ -1670,6 +1671,10 @@ gb_internal bool is_type_raw_union(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
 	return (t->kind == Type_Struct && t->Struct.is_raw_union);
 	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) {
 gb_internal bool is_type_enum(Type *t) {
 	t = base_type(t);
 	t = base_type(t);
 	return (t->kind == Type_Enum);
 	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:
 	case Type_Struct:
 		if (x->Struct.is_raw_union == y->Struct.is_raw_union &&
 		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.fields.count == y->Struct.fields.count &&
 		    x->Struct.is_packed    == y->Struct.is_packed &&
 		    x->Struct.is_packed    == y->Struct.is_packed &&
 		    x->Struct.custom_align == y->Struct.custom_align &&
 		    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");
 		str = gb_string_appendc(str, "struct");
 		if (type->Struct.is_packed)    str = gb_string_appendc(str, " #packed");
 		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_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);
 		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, " {");
 		str = gb_string_appendc(str, " {");