Skip to content

Commit 3c0d450

Browse files
crysbotHertzDevilysbaddaden
authored
Add fallback if __crystal_raise_cast_failed is missing (#15762) (#15769)
Co-authored-by: Quinton Miller <[email protected]> Co-authored-by: Julien Portalier <[email protected]>
1 parent 4b59abc commit 3c0d450

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

src/compiler/crystal/codegen/codegen.cr

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1490,7 +1490,7 @@ module Crystal
14901490
cond cmp, matches_block, doesnt_match_block
14911491

14921492
position_at_end doesnt_match_block
1493-
codegen_raise_cast_failed(type_id, to_type, node)
1493+
codegen_raise_cast_failed(last_value, type_id, obj_type, to_type, node)
14941494

14951495
position_at_end matches_block
14961496
@last = downcast last_value, resulting_type, obj_type, true
@@ -1500,6 +1500,29 @@ module Crystal
15001500
false
15011501
end
15021502

1503+
# fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1504+
def type_cast_exception_call(from_type, to_type, node, var_name)
1505+
pieces = [
1506+
StringLiteral.new("Cast from ").at(node),
1507+
Call.new(Var.new(var_name).at(node), "class").at(node),
1508+
StringLiteral.new(" to #{to_type} failed").at(node),
1509+
] of ASTNode
1510+
1511+
if location = node.location
1512+
pieces << StringLiteral.new(", at #{location.expanded_location}:#{location.line_number}").at(node)
1513+
end
1514+
1515+
ex = Call.new(Path.global("TypeCastError").at(node), "new", StringInterpolation.new(pieces).at(node)).at(node)
1516+
call = Call.global("raise", ex).at(node)
1517+
call = @program.normalize(call)
1518+
1519+
meta_vars = MetaVars.new
1520+
meta_vars[var_name] = MetaVar.new(var_name, type: from_type)
1521+
visitor = MainVisitor.new(@program, meta_vars)
1522+
@program.visit_main call, visitor: visitor
1523+
call
1524+
end
1525+
15031526
def visit(node : NilableCast)
15041527
request_value(node.obj)
15051528

@@ -1555,26 +1578,33 @@ module Crystal
15551578
end
15561579
end
15571580

1558-
def codegen_raise_cast_failed(type_id, to_type, node)
1581+
def codegen_raise_cast_failed(value, type_id, obj_type, to_type, node)
15591582
location = node.location
15601583
set_current_debug_location(location) if location && @debug.line_numbers?
15611584

1562-
func = crystal_raise_cast_failed_fun
1563-
call_args = [
1564-
cast_to_void_pointer(type_id_to_class_name(type_id)),
1565-
cast_to_void_pointer(build_string_constant(to_type.to_s)),
1566-
location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1567-
] of LLVM::Value
1568-
1569-
if (rescue_block = @rescue_block)
1570-
invoke_out_block = new_block "invoke_out"
1571-
invoke func, call_args, invoke_out_block, rescue_block
1572-
position_at_end invoke_out_block
1585+
if func = crystal_raise_cast_failed_fun
1586+
call_args = [
1587+
cast_to_void_pointer(type_id_to_class_name(type_id)),
1588+
cast_to_void_pointer(build_string_constant(to_type.to_s)),
1589+
location ? cast_to_void_pointer(build_string_constant(location.expanded_location.to_s)) : llvm_context.void_pointer.null,
1590+
] of LLVM::Value
1591+
1592+
if (rescue_block = @rescue_block)
1593+
invoke_out_block = new_block "invoke_out"
1594+
invoke func, call_args, invoke_out_block, rescue_block
1595+
position_at_end invoke_out_block
1596+
else
1597+
call func, call_args
1598+
end
1599+
1600+
unreachable
15731601
else
1574-
call func, call_args
1602+
# fallback for stdlib before 1.16.2 when using a 1.16.2 or later compiler
1603+
temp_var_name = @program.new_temp_var_name
1604+
context.vars[temp_var_name] = LLVMVar.new(value, obj_type, already_loaded: true)
1605+
accept type_cast_exception_call(obj_type, to_type, node, temp_var_name)
1606+
context.vars.delete temp_var_name
15751607
end
1576-
1577-
unreachable
15781608
end
15791609

15801610
def type_id_to_class_name(type_id)
@@ -2353,7 +2383,7 @@ module Crystal
23532383
if raise_cast_failed_fun = @raise_cast_failed_fun
23542384
check_main_fun RAISE_CAST_FAILED_NAME, raise_cast_failed_fun
23552385
else
2356-
raise Error.new("Missing __crystal_raise_cast_failed function, either use std-lib's prelude or define it")
2386+
nil
23572387
end
23582388
end
23592389

0 commit comments

Comments
 (0)