summaryrefslogtreecommitdiff
path: root/src/codegen/codegen_utils.c
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-25 11:53:53 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-25 11:53:53 +0000
commit2dc5214fd8bb6a1168e2f2b643a36043c36c908a (patch)
tree55780a330598d3606205b662584a839ea60d0315 /src/codegen/codegen_utils.c
parent6a45f6a640dc8f7b5f9819d22d68cd79fbe3c260 (diff)
Fix for #121
Diffstat (limited to 'src/codegen/codegen_utils.c')
-rw-r--r--src/codegen/codegen_utils.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index 3169eba..38ae409 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -706,3 +706,84 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
fprintf(out, ")");
}
+
+// Invalidate a moved-from variable by zeroing it out to prevent double-free
+int emit_move_invalidation(ParserContext *ctx, ASTNode *node, FILE *out)
+{
+ if (!node)
+ {
+ return 0;
+ }
+
+ // Check if it's a valid l-value we can memset
+ if (node->type != NODE_EXPR_VAR && node->type != NODE_EXPR_MEMBER)
+ {
+ return 0;
+ }
+
+ // Common logic to find type and check Drop
+ char *type_name = infer_type(ctx, node);
+ ASTNode *def = NULL;
+ if (type_name)
+ {
+ char *clean_type = type_name;
+ if (strncmp(clean_type, "struct ", 7) == 0)
+ {
+ clean_type += 7;
+ }
+ def = find_struct_def(ctx, clean_type);
+ }
+
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ if (node->type == NODE_EXPR_VAR)
+ {
+ fprintf(out, "memset(&%s, 0, sizeof(%s))", node->var_ref.name, node->var_ref.name);
+ return 1;
+ }
+ else if (node->type == NODE_EXPR_MEMBER)
+ {
+ // For members: memset(&foo.bar, 0, sizeof(foo.bar))
+ fprintf(out, "memset(&");
+ codegen_expression(ctx, node, out);
+ fprintf(out, ", 0, sizeof(");
+ codegen_expression(ctx, node, out);
+ fprintf(out, "))");
+ return 1;
+ }
+ }
+ return 0;
+}
+
+// Emits expression, wrapping it in a move-invalidation block if it's a consuming variable usage
+void codegen_expression_with_move(ParserContext *ctx, ASTNode *node, FILE *out)
+{
+ if (node && (node->type == NODE_EXPR_VAR || node->type == NODE_EXPR_MEMBER))
+ {
+ // Re-use infer logic to see if we need invalidation
+ char *type_name = infer_type(ctx, node);
+ ASTNode *def = NULL;
+ if (type_name)
+ {
+ char *clean_type = type_name;
+ if (strncmp(clean_type, "struct ", 7) == 0)
+ {
+ clean_type += 7;
+ }
+ def = find_struct_def(ctx, clean_type);
+ }
+
+ if (def && def->type_info && def->type_info->traits.has_drop)
+ {
+ fprintf(out, "({ __typeof__(");
+ codegen_expression(ctx, node, out);
+ fprintf(out, ") _mv = ");
+ codegen_expression(ctx, node, out);
+ fprintf(out, "; ");
+ emit_move_invalidation(ctx, node, out);
+ fprintf(out, "; _mv; })");
+ return;
+ }
+ }
+ codegen_expression(ctx, node, out);
+}