defer is broken when placed before a $foreach #1912

This commit is contained in:
Christoffer Lerno
2025-01-31 14:39:51 +01:00
parent 7dd9256e2d
commit 9092defd46
15 changed files with 432 additions and 104 deletions

View File

@@ -0,0 +1,258 @@
// #target: macos-x64
module test;
import std;
// Issue #1912
fn void test()
{
defer io::printn("World!");
const HELLO = "Hello";
$for (var $i = 0; $i < 5; $i++)
io::printf("%c", HELLO[$i]);
$endfor
}
fn void main()
{
defer io::printn("World!");
$foreach ($c : "Hello")
io::printf("%c", $c);
$endforeach
io::printn();
}
/* #expect: test.ll
define void @test.test() #0 {
entry:
%varargslots = alloca [1 x %any], align 16
%taddr = alloca i8, align 1
%retparam = alloca i64, align 8
%varargslots1 = alloca [1 x %any], align 16
%taddr2 = alloca i8, align 1
%retparam3 = alloca i64, align 8
%varargslots4 = alloca [1 x %any], align 16
%taddr5 = alloca i8, align 1
%retparam6 = alloca i64, align 8
%varargslots7 = alloca [1 x %any], align 16
%taddr8 = alloca i8, align 1
%retparam9 = alloca i64, align 8
%varargslots10 = alloca [1 x %any], align 16
%taddr11 = alloca i8, align 1
%retparam12 = alloca i64, align 8
%len = alloca i64, align 8
%error_var = alloca i64, align 8
%retparam14 = alloca i64, align 8
%error_var15 = alloca i64, align 8
%error_var21 = alloca i64, align 8
store i8 72, ptr %taddr, align 1
%0 = insertvalue %any undef, ptr %taddr, 0
%1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %1, ptr %varargslots, align 16
%2 = call i64 @std.io.printf(ptr %retparam, ptr @.str.1, i64 2, ptr %varargslots, i64 1)
store i8 101, ptr %taddr2, align 1
%3 = insertvalue %any undef, ptr %taddr2, 0
%4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %4, ptr %varargslots1, align 16
%5 = call i64 @std.io.printf(ptr %retparam3, ptr @.str.2, i64 2, ptr %varargslots1, i64 1)
store i8 108, ptr %taddr5, align 1
%6 = insertvalue %any undef, ptr %taddr5, 0
%7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %7, ptr %varargslots4, align 16
%8 = call i64 @std.io.printf(ptr %retparam6, ptr @.str.3, i64 2, ptr %varargslots4, i64 1)
store i8 108, ptr %taddr8, align 1
%9 = insertvalue %any undef, ptr %taddr8, 0
%10 = insertvalue %any %9, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %10, ptr %varargslots7, align 16
%11 = call i64 @std.io.printf(ptr %retparam9, ptr @.str.4, i64 2, ptr %varargslots7, i64 1)
store i8 111, ptr %taddr11, align 1
%12 = insertvalue %any undef, ptr %taddr11, 0
%13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %13, ptr %varargslots10, align 16
%14 = call i64 @std.io.printf(ptr %retparam12, ptr @.str.5, i64 2, ptr %varargslots10, i64 1)
%15 = call ptr @std.io.stdout()
%16 = call i64 @std.io.File.write(ptr %retparam14, ptr %15, ptr @.str.6, i64 6)
%not_err = icmp eq i64 %16, 0
%17 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %17, label %after_check, label %assign_optional
assign_optional: ; preds = %entry
store i64 %16, ptr %error_var, align 8
br label %guard_block
after_check: ; preds = %entry
br label %noerr_block
guard_block: ; preds = %assign_optional
br label %voiderr
noerr_block: ; preds = %after_check
%18 = load i64, ptr %retparam14, align 8
store i64 %18, ptr %len, align 8
%19 = call i64 @std.io.File.write_byte(ptr %15, i8 zeroext 10)
%not_err16 = icmp eq i64 %19, 0
%20 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
br i1 %20, label %after_check18, label %assign_optional17
assign_optional17: ; preds = %noerr_block
store i64 %19, ptr %error_var15, align 8
br label %guard_block19
after_check18: ; preds = %noerr_block
br label %noerr_block20
guard_block19: ; preds = %assign_optional17
br label %voiderr
noerr_block20: ; preds = %after_check18
%21 = call i64 @std.io.File.flush(ptr %15)
%not_err22 = icmp eq i64 %21, 0
%22 = call i1 @llvm.expect.i1(i1 %not_err22, i1 true)
br i1 %22, label %after_check24, label %assign_optional23
assign_optional23: ; preds = %noerr_block20
store i64 %21, ptr %error_var21, align 8
br label %guard_block25
after_check24: ; preds = %noerr_block20
br label %noerr_block26
guard_block25: ; preds = %assign_optional23
br label %voiderr
noerr_block26: ; preds = %after_check24
%23 = load i64, ptr %len, align 8
%add = add i64 %23, 1
br label %voiderr
voiderr: ; preds = %noerr_block26, %guard_block25, %guard_block19, %guard_block
ret void
}
define void @test.main() #0 {
entry:
%varargslots = alloca [1 x %any], align 16
%taddr = alloca i8, align 1
%retparam = alloca i64, align 8
%varargslots1 = alloca [1 x %any], align 16
%taddr2 = alloca i8, align 1
%retparam3 = alloca i64, align 8
%varargslots4 = alloca [1 x %any], align 16
%taddr5 = alloca i8, align 1
%retparam6 = alloca i64, align 8
%varargslots7 = alloca [1 x %any], align 16
%taddr8 = alloca i8, align 1
%retparam9 = alloca i64, align 8
%varargslots10 = alloca [1 x %any], align 16
%taddr11 = alloca i8, align 1
%retparam12 = alloca i64, align 8
%len = alloca i64, align 8
%error_var = alloca i64, align 8
%retparam14 = alloca i64, align 8
%error_var15 = alloca i64, align 8
%error_var21 = alloca i64, align 8
%len27 = alloca i64, align 8
%error_var28 = alloca i64, align 8
%retparam30 = alloca i64, align 8
%error_var36 = alloca i64, align 8
%error_var42 = alloca i64, align 8
store i8 72, ptr %taddr, align 1
%0 = insertvalue %any undef, ptr %taddr, 0
%1 = insertvalue %any %0, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %1, ptr %varargslots, align 16
%2 = call i64 @std.io.printf(ptr %retparam, ptr @.str.7, i64 2, ptr %varargslots, i64 1)
store i8 101, ptr %taddr2, align 1
%3 = insertvalue %any undef, ptr %taddr2, 0
%4 = insertvalue %any %3, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %4, ptr %varargslots1, align 16
%5 = call i64 @std.io.printf(ptr %retparam3, ptr @.str.8, i64 2, ptr %varargslots1, i64 1)
store i8 108, ptr %taddr5, align 1
%6 = insertvalue %any undef, ptr %taddr5, 0
%7 = insertvalue %any %6, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %7, ptr %varargslots4, align 16
%8 = call i64 @std.io.printf(ptr %retparam6, ptr @.str.9, i64 2, ptr %varargslots4, i64 1)
store i8 108, ptr %taddr8, align 1
%9 = insertvalue %any undef, ptr %taddr8, 0
%10 = insertvalue %any %9, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %10, ptr %varargslots7, align 16
%11 = call i64 @std.io.printf(ptr %retparam9, ptr @.str.10, i64 2, ptr %varargslots7, i64 1)
store i8 111, ptr %taddr11, align 1
%12 = insertvalue %any undef, ptr %taddr11, 0
%13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.char" to i64), 1
store %any %13, ptr %varargslots10, align 16
%14 = call i64 @std.io.printf(ptr %retparam12, ptr @.str.11, i64 2, ptr %varargslots10, i64 1)
%15 = call ptr @std.io.stdout()
%16 = call i64 @std.io.File.write(ptr %retparam14, ptr %15, ptr null, i64 0)
%not_err = icmp eq i64 %16, 0
%17 = call i1 @llvm.expect.i1(i1 %not_err, i1 true)
br i1 %17, label %after_check, label %assign_optional
assign_optional: ; preds = %entry
store i64 %16, ptr %error_var, align 8
br label %guard_block
after_check: ; preds = %entry
br label %noerr_block
guard_block: ; preds = %assign_optional
br label %voiderr
noerr_block: ; preds = %after_check
%18 = load i64, ptr %retparam14, align 8
store i64 %18, ptr %len, align 8
%19 = call i64 @std.io.File.write_byte(ptr %15, i8 zeroext 10)
%not_err16 = icmp eq i64 %19, 0
%20 = call i1 @llvm.expect.i1(i1 %not_err16, i1 true)
br i1 %20, label %after_check18, label %assign_optional17
assign_optional17: ; preds = %noerr_block
store i64 %19, ptr %error_var15, align 8
br label %guard_block19
after_check18: ; preds = %noerr_block
br label %noerr_block20
guard_block19: ; preds = %assign_optional17
br label %voiderr
noerr_block20: ; preds = %after_check18
%21 = call i64 @std.io.File.flush(ptr %15)
%not_err22 = icmp eq i64 %21, 0
%22 = call i1 @llvm.expect.i1(i1 %not_err22, i1 true)
br i1 %22, label %after_check24, label %assign_optional23
assign_optional23: ; preds = %noerr_block20
store i64 %21, ptr %error_var21, align 8
br label %guard_block25
after_check24: ; preds = %noerr_block20
br label %noerr_block26
guard_block25: ; preds = %assign_optional23
br label %voiderr
noerr_block26: ; preds = %after_check24
%23 = load i64, ptr %len, align 8
%add = add i64 %23, 1
br label %voiderr
voiderr: ; preds = %noerr_block26, %guard_block25, %guard_block19, %guard_block
%24 = call ptr @std.io.stdout()
%25 = call i64 @std.io.File.write(ptr %retparam30, ptr %24, ptr @.str.12, i64 6)
%not_err31 = icmp eq i64 %25, 0
%26 = call i1 @llvm.expect.i1(i1 %not_err31, i1 true)
br i1 %26, label %after_check33, label %assign_optional32
assign_optional32: ; preds = %voiderr
store i64 %25, ptr %error_var28, align 8
br label %guard_block34
after_check33: ; preds = %voiderr
br label %noerr_block35
guard_block34: ; preds = %assign_optional32
br label %voiderr49
noerr_block35: ; preds = %after_check33
%27 = load i64, ptr %retparam30, align 8
store i64 %27, ptr %len27, align 8
%28 = call i64 @std.io.File.write_byte(ptr %24, i8 zeroext 10)
%not_err37 = icmp eq i64 %28, 0
%29 = call i1 @llvm.expect.i1(i1 %not_err37, i1 true)
br i1 %29, label %after_check39, label %assign_optional38
assign_optional38: ; preds = %noerr_block35
store i64 %28, ptr %error_var36, align 8
br label %guard_block40
after_check39: ; preds = %noerr_block35
br label %noerr_block41
guard_block40: ; preds = %assign_optional38
br label %voiderr49
noerr_block41: ; preds = %after_check39
%30 = call i64 @std.io.File.flush(ptr %24)
%not_err43 = icmp eq i64 %30, 0
%31 = call i1 @llvm.expect.i1(i1 %not_err43, i1 true)
br i1 %31, label %after_check45, label %assign_optional44
assign_optional44: ; preds = %noerr_block41
store i64 %30, ptr %error_var42, align 8
br label %guard_block46
after_check45: ; preds = %noerr_block41
br label %noerr_block47
guard_block46: ; preds = %assign_optional44
br label %voiderr49
noerr_block47: ; preds = %after_check45
%32 = load i64, ptr %len27, align 8
%add48 = add i64 %32, 1
br label %voiderr49
voiderr49: ; preds = %noerr_block47, %guard_block46, %guard_block40, %guard_block34
ret void
}

View File

@@ -16,15 +16,14 @@ fn void main() {
/* #expect: test.ll
define void @test.foo() #0 !dbg !8 {
entry:
%values = alloca [1 x i32], align 4
call void @llvm.dbg.declare(metadata ptr %values, metadata !12, metadata !DIExpression()), !dbg !17
store i32 0, ptr %values, align 4, !dbg !17
store i32 0, ptr %values, align 4, !dbg !18
ret void, !dbg !18
}
!0 = !{i32 2, !"Dwarf Version", i32 4}
!1 = !{i32 2, !"Debug Info Version", i32 3}
!2 = !{i32 2, !"wchar_size", i32 4}
@@ -43,21 +42,15 @@ entry:
!15 = !{!16}
!16 = !DISubrange(count: 1, lowerBound: 0)
!17 = !DILocation(line: 5, column: 10, scope: !8)
!18 = !DILocation(line: 7, column: 18, scope: !19)
!19 = distinct !DILexicalBlock(scope: !20, file: !7, line: 6, column: 3)
!20 = distinct !DILexicalBlock(scope: !8, file: !7, line: 6, column: 3)
!21 = distinct !DISubprogram(name: "main", linkageName: "test.main", scope: !7, file: !7, line: 11, type: !9, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6)
!22 = !DILocation(line: 12, column: 3, scope: !21)
!23 = distinct !DISubprogram(name: "_$main", linkageName: "main", scope: !7, file: !7, line: 11, type: !24, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !11)
!24 = !DISubroutineType(types: !25)
!25 = !{!14, !14, !26}
!26 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char**", baseType: !27, size: 64, align: 64, dwarfAddressSpace: 0)
!27 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char*", baseType: !28, size: 64, align: 64, dwarfAddressSpace: 0)
!28 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!29 = !DILocalVariable(name: ".anon", arg: 1, scope: !23, file: !7, line: 11, type: !14)
!30 = !DILocation(line: 11, column: 9, scope: !23)
!31 = !DILocalVariable(name: ".anon", arg: 2, scope: !23, file: !7, line: 11, type: !26)
!32 = !DILocation(line: 18, column: 2, scope: !33, inlinedAt: !30)
!33 = distinct !DISubprogram(name: "@main_to_void_main", linkageName: "@main_to_void_main", scope: !34, file: !34, line: 16, scopeLine: 16, spFlags: DISPFlagLocalToUnit | DISPFlagDefinition, unit: !6)
!34 = !DIFile(filename: "main_stub.c3"
!35 = !DILocation(line: 19, column: 9, scope: !33, inlinedAt: !30)
!18 = !DILocation(line: 7, column: 18, scope: !8)
!19 = distinct !DISubprogram(name: "main", linkageName: "test.main", scope: !7, file: !7, line: 11, type: !9, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6)
!20 = !DILocation(line: 12, column: 3, scope: !19)
!21 = distinct !DISubprogram(name: "_$main", linkageName: "main", scope: !7, file: !7, line: 11, type: !22, scopeLine: 11, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !11)
!22 = !DISubroutineType(types: !23)
!23 = !{!14, !14, !24}
!24 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char**", baseType: !25, size: 64, align: 64, dwarfAddressSpace: 0)
!25 = !DIDerivedType(tag: DW_TAG_pointer_type, name: "char*", baseType: !26, size: 64, align: 64, dwarfAddressSpace: 0)
!26 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_unsigned_char)
!27 = !DILocalVariable(name: ".anon", arg: 1, scope: !21, file: !7, line: 11, type: !14)
!28 = !DILocation(line: 11, column: 9, scope: !21)
!29 = !DILocalVariable(name: ".anon", arg: 2, scope: !21, file: !7, line: 11, type: !24)