Browse Source

Add error message for atomic intrinsics to prevent arbitrary types

gingerBill 2 years ago
parent
commit
c819c350d6
2 changed files with 45 additions and 0 deletions
  1. 34 0
      src/check_builtin.cpp
  2. 11 0
      src/check_expr.cpp

+ 34 - 0
src/check_builtin.cpp

@@ -1188,6 +1188,15 @@ gb_internal bool is_valid_type_for_load(Type *type) {
 	return false;
 }
 
+gb_internal bool check_atomic_ptr_argument(Operand *operand, String const &builtin_name, Type *elem) {
+	if (!is_type_valid_atomic_type(elem)) {
+		error(operand->expr, "Only an integer, floating-point, boolean, or pointer can be used as an atomic for '%.*s'", LIT(builtin_name));
+		return false;
+	}
+	return true;
+
+}
+
 gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
 	ast_node(ce, CallExpr, call);
 	ast_node(bd, BasicDirective, ce->proc);
@@ -4246,6 +4255,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (id == BuiltinProc_atomic_store && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 			Operand x = {};
 			check_expr_with_type_hint(c, &x, ce->args[1], elem);
 			check_assignment(c, &x, elem, builtin_name);
@@ -4262,6 +4274,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 			Operand x = {};
 			check_expr_with_type_hint(c, &x, ce->args[1], elem);
 			check_assignment(c, &x, elem, builtin_name);
@@ -4294,6 +4309,10 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (id == BuiltinProc_atomic_load && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
+
 			operand->type = elem;
 			operand->mode = Addressing_Value;
 			break;
@@ -4306,6 +4325,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 
 			OdinAtomicMemoryOrder memory_order = {};
 			if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &memory_order)) {
@@ -4337,6 +4359,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 			Operand x = {};
 			check_expr_with_type_hint(c, &x, ce->args[1], elem);
 			check_assignment(c, &x, elem, builtin_name);
@@ -4374,6 +4399,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 			Operand x = {};
 			check_expr_with_type_hint(c, &x, ce->args[1], elem);
 			check_assignment(c, &x, elem, builtin_name);
@@ -4412,6 +4440,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 			Operand x = {};
 			Operand y = {};
 			check_expr_with_type_hint(c, &x, ce->args[1], elem);
@@ -4439,6 +4470,9 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
 				error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
 				return false;
 			}
+			if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
+				return false;
+			}
 			Operand x = {};
 			Operand y = {};
 			check_expr_with_type_hint(c, &x, ce->args[1], elem);

+ 11 - 0
src/check_expr.cpp

@@ -4896,6 +4896,17 @@ gb_internal bool is_type_normal_pointer(Type *ptr, Type **elem) {
 	return false;
 }
 
+gb_internal bool is_type_valid_atomic_type(Type *elem) {
+	elem = core_type(elem);
+	if (elem->kind == Type_BitSet) {
+		elem = bit_set_to_int(elem);
+	}
+	if (elem->kind != Type_Basic) {
+		return false;
+	}
+	return (elem->Basic.flags & (BasicFlag_Boolean|BasicFlag_OrderedNumeric)) != 0;
+}
+
 gb_internal bool check_identifier_exists(Scope *s, Ast *node, bool nested = false, Scope **out_scope = nullptr) {
 	switch (node->kind) {
 	case_ast_node(i, Ident, node);