aboutsummaryrefslogtreecommitdiff
path: root/src/check_builtin.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2022-03-31 00:49:53 +0100
committergingerBill <bill@gingerbill.org>2022-03-31 00:49:53 +0100
commit6bc0c611abf9426815207d06c8f1d922533b278b (patch)
treefdb1308431dda1605497f3eb5bc275a247c913e7 /src/check_builtin.cpp
parentba1930eb01455f3f8f84a24b8438171555611b95 (diff)
Enforce success failure pairings of `compare_exchange_*_explicit` at compile time
Diffstat (limited to 'src/check_builtin.cpp')
-rw-r--r--src/check_builtin.cpp92
1 files changed, 85 insertions, 7 deletions
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 3fe0f1048..a82577b31 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -379,7 +379,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
}
}
-bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, char const *extra_message = nullptr) {
+bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, OdinAtomicMemoryOrder *memory_order_, char const *extra_message = nullptr) {
Operand x = {};
check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order);
if (x.mode == Addressing_Invalid) {
@@ -400,6 +400,9 @@ bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String con
error(x.expr, "Illegal Atomic_Memory_Order value, got %lld", cast(long long)value);
return false;
}
+ if (memory_order_) {
+ *memory_order_ = cast(OdinAtomicMemoryOrder)value;
+ }
return true;
@@ -3232,7 +3235,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case BuiltinProc_atomic_thread_fence:
case BuiltinProc_atomic_signal_fence:
- if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name)) {
+ if (!check_atomic_memory_order_argument(c, ce->args[0], builtin_name, nullptr)) {
return false;
}
operand->mode = Addressing_NoValue;
@@ -3269,9 +3272,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
check_expr_with_type_hint(c, &x, ce->args[1], elem);
check_assignment(c, &x, elem, builtin_name);
- if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name)) {
+ OdinAtomicMemoryOrder memory_order = {};
+ if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name, &memory_order)) {
return false;
}
+ switch (memory_order) {
+ case OdinAtomicMemoryOrder_consume:
+ case OdinAtomicMemoryOrder_acquire:
+ case OdinAtomicMemoryOrder_acq_rel:
+ error(ce->args[2], "Illegal memory order .%s for %.*s", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name));
+ break;
+ }
operand->type = nullptr;
operand->mode = Addressing_NoValue;
@@ -3303,10 +3314,18 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
return false;
}
- if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name)) {
+ OdinAtomicMemoryOrder memory_order = {};
+ if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &memory_order)) {
return false;
}
+ switch (memory_order) {
+ case OdinAtomicMemoryOrder_release:
+ case OdinAtomicMemoryOrder_acq_rel:
+ error(ce->args[1], "Illegal memory order .%s for %.*s", OdinAtomicMemoryOrder_strings[memory_order], LIT(builtin_name));
+ break;
+ }
+
operand->type = elem;
operand->mode = Addressing_Value;
break;
@@ -3352,7 +3371,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
check_assignment(c, &x, elem, builtin_name);
- if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name)) {
+ if (!check_atomic_memory_order_argument(c, ce->args[2], builtin_name, nullptr)) {
return false;
}
@@ -3396,13 +3415,72 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
check_assignment(c, &x, elem, builtin_name);
check_assignment(c, &y, elem, builtin_name);
- if (!check_atomic_memory_order_argument(c, ce->args[3], builtin_name, "success ordering")) {
+ OdinAtomicMemoryOrder success_memory_order = {};
+ OdinAtomicMemoryOrder failure_memory_order = {};
+ if (!check_atomic_memory_order_argument(c, ce->args[3], builtin_name, &success_memory_order, "success ordering")) {
return false;
}
- if (!check_atomic_memory_order_argument(c, ce->args[4], builtin_name, "failure ordering")) {
+ if (!check_atomic_memory_order_argument(c, ce->args[4], builtin_name, &failure_memory_order, "failure ordering")) {
return false;
}
+ bool invalid_combination = false;
+
+ switch (success_memory_order) {
+ case OdinAtomicMemoryOrder_relaxed:
+ case OdinAtomicMemoryOrder_release:
+ if (failure_memory_order != OdinAtomicMemoryOrder_relaxed) {
+ invalid_combination = true;
+ }
+ break;
+ case OdinAtomicMemoryOrder_consume:
+ switch (failure_memory_order) {
+ case OdinAtomicMemoryOrder_relaxed:
+ case OdinAtomicMemoryOrder_consume:
+ break;
+ default:
+ invalid_combination = true;
+ break;
+ }
+ break;
+ case OdinAtomicMemoryOrder_acquire:
+ case OdinAtomicMemoryOrder_acq_rel:
+ switch (failure_memory_order) {
+ case OdinAtomicMemoryOrder_relaxed:
+ case OdinAtomicMemoryOrder_consume:
+ case OdinAtomicMemoryOrder_acquire:
+ break;
+ default:
+ invalid_combination = true;
+ break;
+ }
+ break;
+ case OdinAtomicMemoryOrder_seq_cst:
+ switch (failure_memory_order) {
+ case OdinAtomicMemoryOrder_relaxed:
+ case OdinAtomicMemoryOrder_consume:
+ case OdinAtomicMemoryOrder_acquire:
+ case OdinAtomicMemoryOrder_seq_cst:
+ break;
+ default:
+ invalid_combination = true;
+ break;
+ }
+ break;
+ default:
+ invalid_combination = true;
+ break;
+ }
+
+
+ if (invalid_combination) {
+ error(ce->args[3], "Illegal memory order pairing for %.*s, success = .%s, failure = .%s",
+ LIT(builtin_name),
+ OdinAtomicMemoryOrder_strings[success_memory_order],
+ OdinAtomicMemoryOrder_strings[failure_memory_order]
+ );
+ }
+
operand->mode = Addressing_OptionalOk;
operand->type = elem;
break;