Skip to content

Commit 8e802e8

Browse files
r41k0uclaude
andcommitted
Core: Return through the same value path as every other consumer
A pointer used where a value is expected is dereferenced to it, with a null check, in helper arguments, printk arguments, binary-operation operands and comparisons, all through deref_to_depth. return was the one consumer that never joined that convention, so `return p` on a map lookup emitted `ret i64*` and left it to llc to reject. handle_return now goes through get_typed_operand, which is that path, and converts the result to the declared return type like the augmented-assignment store does. convert() no longer passes a non-integer through silently: every caller either checks both sides or is on an integer-only path, so what reaches that branch is a type error, and it is raised with both types named instead of surfacing from llc with an IR line number. Returning a struct value is the case that now fails at compile time. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 parent 359ddbd commit 8e802e8

2 files changed

Lines changed: 14 additions & 9 deletions

File tree

‎pythonbpf/expr/type_normalization.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ def convert(builder, val, from_ty, to_ty):
5353
value itself, which may already be wider than its descriptor says.
5454
"""
5555
if not (isinstance(to_ty, ir.IntType) and isinstance(val.type, ir.IntType)):
56-
return val
56+
# Every caller either checks both sides are integers or sits on a path
57+
# that only carries integers, so reaching here is a type error that
58+
# would otherwise surface as an llc rejection with no Python line.
59+
raise TypeError(
60+
f"integer conversion requested for a {val.type} value to {to_ty}"
61+
)
5762
if val.type.width > to_ty.width:
5863
return builder.trunc(val, to_ty)
5964
if val.type.width < to_ty.width:

‎pythonbpf/functions/functions_pass.py‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,9 @@ def handle_if(func, compilation_context, builder, stmt, local_sym_tab):
333333
builder.position_at_end(merge_block)
334334

335335

336-
def handle_return(builder, stmt, local_sym_tab, ret_type, compilation_context=None):
336+
def handle_return(
337+
func, builder, stmt, local_sym_tab, ret_type, compilation_context=None
338+
):
337339
logger.info(f"Handling return statement: {ast.dump(stmt)}")
338340
if stmt.value is None:
339341
return handle_none_return(builder)
@@ -358,12 +360,10 @@ def handle_return(builder, stmt, local_sym_tab, ret_type, compilation_context=No
358360
"CompilationContext required for return statement evaluation"
359361
)
360362

361-
val = eval_expr(
362-
func=None,
363-
compilation_context=compilation_context,
364-
builder=builder,
365-
expr=stmt.value,
366-
local_sym_tab=local_sym_tab,
363+
# A pointer to a value is dereferenced to it (null-checked), the way
364+
# every other consumer of a value does; get_typed_operand is that path.
365+
val = get_typed_operand(
366+
func, compilation_context, stmt.value, builder, local_sym_tab
367367
)
368368
logger.info(f"Evaluated return expression to {val}")
369369
# The declared return type is the LHS of an implicit assignment:
@@ -403,7 +403,7 @@ def process_stmt(
403403
handle_if(func, compilation_context, builder, stmt, local_sym_tab)
404404
elif isinstance(stmt, ast.Return):
405405
did_return = handle_return(
406-
builder, stmt, local_sym_tab, ret_type, compilation_context
406+
func, builder, stmt, local_sym_tab, ret_type, compilation_context
407407
)
408408
else:
409409
# Silently dropping a statement makes the program mean something other

0 commit comments

Comments
 (0)