aboutsummaryrefslogtreecommitdiff
path: root/src/check_expr.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2024-06-29 12:02:31 +0100
committergingerBill <bill@gingerbill.org>2024-06-29 12:02:31 +0100
commit4b71c47fd5e70f0f96e139e17637cf5de1beb2fc (patch)
tree8540dd126a0e18b12c40864433c23dcd2a980f45 /src/check_expr.cpp
parent704530497b166dfa6fcee8f2c95a9e492a78a024 (diff)
Check for unneeded `transmute` with `-vet-cast`
Diffstat (limited to 'src/check_expr.cpp')
-rw-r--r--src/check_expr.cpp38
1 files changed, 26 insertions, 12 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 2fa491417..45500e79a 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -3396,7 +3396,7 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb
) {
gbString oper_str = expr_to_string(x->expr);
gbString to_type = type_to_string(dst_exact);
- error(x->expr, "Unneeded cast of `%s` to identical type `%s`", oper_str, to_type);
+ error(x->expr, "Unneeded cast of '%s' to identical type '%s'", oper_str, to_type);
gb_string_free(oper_str);
gb_string_free(to_type);
}
@@ -3406,22 +3406,13 @@ gb_internal void check_cast(CheckerContext *c, Operand *x, Type *type, bool forb
x->type = type;
}
-gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t) {
+gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type *t, bool forbid_identical = false) {
if (!is_operand_value(*o)) {
error(o->expr, "'transmute' can only be applied to values");
o->mode = Addressing_Invalid;
return false;
}
- // if (o->mode == Addressing_Constant) {
- // gbString expr_str = expr_to_string(o->expr);
- // error(o->expr, "Cannot transmute a constant expression: '%s'", expr_str);
- // gb_string_free(expr_str);
- // o->mode = Addressing_Invalid;
- // o->expr = node;
- // return false;
- // }
-
Type *src_t = o->type;
Type *dst_t = t;
Type *src_bt = base_type(src_t);
@@ -3504,6 +3495,29 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
return true;
}
}
+ } else {
+ // If we check polymorphic procedures, we risk erring on
+ // identical casts that cannot be foreseen or otherwise
+ // forbidden, so just skip them.
+ if (forbid_identical && check_vet_flags(c) & VetFlag_Cast &&
+ (c->curr_proc_sig == nullptr || !is_type_polymorphic(c->curr_proc_sig))) {
+ bool is_runtime = false;
+ if (c->pkg && (c->pkg->kind == Package_Runtime || c->pkg->kind == Package_Builtin)) {
+ is_runtime = true;
+ }
+ if (are_types_identical(src_t, dst_t) && !is_runtime) {
+ gbString oper_str = expr_to_string(o->expr);
+ gbString to_type = type_to_string(dst_t);
+ error(o->expr, "Unneeded transmute of '%s' to identical type '%s'", oper_str, to_type);
+ gb_string_free(oper_str);
+ gb_string_free(to_type);
+ } else if (is_type_internally_pointer_like(src_t) &&
+ is_type_internally_pointer_like(dst_t)) {
+ gbString to_type = type_to_string(dst_t);
+ error(o->expr, "Use of 'transmute' where 'cast' would be preferred since the types are pointer-like", to_type);
+ gb_string_free(to_type);
+ }
+ }
}
o->mode = Addressing_Value;
@@ -10734,7 +10748,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
if (o->mode != Addressing_Invalid) {
switch (tc->token.kind) {
case Token_transmute:
- check_transmute(c, node, o, type);
+ check_transmute(c, node, o, type, true);
break;
case Token_cast:
check_cast(c, o, type, true);