Browse Source

Add sanity conversion check for integer to quaternion

gingerBill 4 years ago
parent
commit
ebcabb8a27
2 changed files with 42 additions and 21 deletions
  1. 23 21
      src/check_expr.cpp
  2. 19 0
      src/llvm_backend.cpp

+ 23 - 21
src/check_expr.cpp

@@ -2929,6 +2929,7 @@ void check_binary_expr(CheckerContext *c, Operand *x, Ast *node, Type *type_hint
 void update_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) {
 void update_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) {
 	GB_ASSERT(e != nullptr);
 	GB_ASSERT(e != nullptr);
 	gb_mutex_lock(&c->info->untyped_mutex);
 	gb_mutex_lock(&c->info->untyped_mutex);
+	defer (gb_mutex_unlock(&c->info->untyped_mutex));
 	ExprInfo *old = check_get_expr_info(c->info, e);
 	ExprInfo *old = check_get_expr_info(c->info, e);
 	if (old == nullptr) {
 	if (old == nullptr) {
 		if (type != nullptr && type != t_invalid) {
 		if (type != nullptr && type != t_invalid) {
@@ -2939,26 +2940,6 @@ void update_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) {
 		return;
 		return;
 	}
 	}
 
 
-	if (!final && is_type_untyped(type)) {
-		old->type = base_type(type);
-	} else {
-
-		// We need to remove it and then give it a new one
-		map_remove(&c->info->untyped, hash_node(e));
-
-		if (old->is_lhs && !is_type_integer(type)) {
-			gbString expr_str = expr_to_string(e);
-			gbString type_str = type_to_string(type);
-			error(e, "Shifted operand %s must be an integer, got %s", expr_str, type_str);
-			gb_string_free(type_str);
-			gb_string_free(expr_str);
-			return;
-		}
-
-		add_type_and_value(c->info, e, old->mode, type, old->value);
-	}
-	gb_mutex_unlock(&c->info->untyped_mutex);
-
 	switch (e->kind) {
 	switch (e->kind) {
 	case_ast_node(ue, UnaryExpr, e);
 	case_ast_node(ue, UnaryExpr, e);
 		if (old->value.kind != ExactValue_Invalid) {
 		if (old->value.kind != ExactValue_Invalid) {
@@ -3009,6 +2990,25 @@ void update_expr_type(CheckerContext *c, Ast *e, Type *type, bool final) {
 		update_expr_type(c, pe->expr, type, final);
 		update_expr_type(c, pe->expr, type, final);
 	case_end;
 	case_end;
 	}
 	}
+
+	if (!final && is_type_untyped(type)) {
+		old->type = base_type(type);
+		return;
+	}
+
+	// We need to remove it and then give it a new one
+	map_remove(&c->info->untyped, hash_node(e));
+
+	if (old->is_lhs && !is_type_integer(type)) {
+		gbString expr_str = expr_to_string(e);
+		gbString type_str = type_to_string(type);
+		error(e, "Shifted operand %s must be an integer, got %s", expr_str, type_str);
+		gb_string_free(type_str);
+		gb_string_free(expr_str);
+		return;
+	}
+
+	add_type_and_value(c->info, e, old->mode, type, old->value);
 }
 }
 
 
 void update_expr_value(CheckerContext *c, Ast *e, ExactValue value) {
 void update_expr_value(CheckerContext *c, Ast *e, ExactValue value) {
@@ -3247,7 +3247,9 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
 						if (i > 0 && count > 2) error_line(", ");
 						if (i > 0 && count > 2) error_line(", ");
 						if (i == count-1) {
 						if (i == count-1) {
 							if (count == 2) error_line(" ");
 							if (count == 2) error_line(" ");
-							error_line("or ");
+							if (count > 1) {
+								error_line("or ");
+							}
 						}
 						}
 						gbString str = type_to_string(v);
 						gbString str = type_to_string(v);
 						error_line("'%s'", str);
 						error_line("'%s'", str);

+ 19 - 0
src/llvm_backend.cpp

@@ -8106,6 +8106,14 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 		return lb_addr_load(p, gen);
 		return lb_addr_load(p, gen);
 	}
 	}
 
 
+	if (is_type_integer(src) && is_type_complex(dst)) {
+		Type *ft = base_complex_elem_type(dst);
+		lbAddr gen = lb_add_local_generated(p, dst, true);
+		lbValue gp = lb_addr_get_ptr(p, gen);
+		lbValue real = lb_emit_conv(p, value, ft);
+		lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real);
+		return lb_addr_load(p, gen);
+	}
 	if (is_type_float(src) && is_type_complex(dst)) {
 	if (is_type_float(src) && is_type_complex(dst)) {
 		Type *ft = base_complex_elem_type(dst);
 		Type *ft = base_complex_elem_type(dst);
 		lbAddr gen = lb_add_local_generated(p, dst, true);
 		lbAddr gen = lb_add_local_generated(p, dst, true);
@@ -8114,6 +8122,17 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
 		lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real);
 		lb_emit_store(p, lb_emit_struct_ep(p, gp, 0), real);
 		return lb_addr_load(p, gen);
 		return lb_addr_load(p, gen);
 	}
 	}
+
+
+	if (is_type_integer(src) && is_type_quaternion(dst)) {
+		Type *ft = base_complex_elem_type(dst);
+		lbAddr gen = lb_add_local_generated(p, dst, true);
+		lbValue gp = lb_addr_get_ptr(p, gen);
+		lbValue real = lb_emit_conv(p, value, ft);
+		// @QuaternionLayout
+		lb_emit_store(p, lb_emit_struct_ep(p, gp, 3), real);
+		return lb_addr_load(p, gen);
+	}
 	if (is_type_float(src) && is_type_quaternion(dst)) {
 	if (is_type_float(src) && is_type_quaternion(dst)) {
 		Type *ft = base_complex_elem_type(dst);
 		Type *ft = base_complex_elem_type(dst);
 		lbAddr gen = lb_add_local_generated(p, dst, true);
 		lbAddr gen = lb_add_local_generated(p, dst, true);