Просмотр исходного кода

Fix crash in lowering vptr initialization (#5184)

Seems the instructions got emitted out of order & that caused problems
for lowering. This was because most of the initialization instructions
were added to a PendingBlock, but the vptr initialization instructions
were added to the (non-pending) block directly.

(I don't fully understand the pending stuff (is there a different test I
could/should write that demonstrates the vptr init instructions not
being discarded because they didn't go in the pending block (before this
patch)), or the out of order instruction problem (could we add more
robust checking for instruction ordering?) - but perhaps this is
adequate understanding for this bug fix at least)

Fixes #5094

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
David Blaikie 1 год назад
Родитель
Сommit
45d042cab8
2 измененных файлов с 55 добавлено и 1 удалено
  1. 4 1
      toolchain/check/convert.cpp
  2. 51 0
      toolchain/lower/testdata/class/virtual.carbon

+ 4 - 1
toolchain/check/convert.cpp

@@ -500,7 +500,10 @@ static auto ConvertStructToStructOrClass(Context& context,
                             dest_elem_fields.size()});
   for (auto [i, dest_field] : llvm::enumerate(dest_elem_fields)) {
     if (dest_field.name_id == SemIR::NameId::Vptr) {
-      // CARBON_CHECK(ToClass, "Only classes should have vptrs.");
+      if constexpr (!ToClass) {
+        CARBON_FATAL("Only classes should have vptrs.");
+      }
+      target.init_block->InsertHere();
       auto dest_id =
           AddInst<SemIR::ClassElementAccess>(context, value_loc_id,
                                              {.type_id = dest_field.type_id,

+ 51 - 0
toolchain/lower/testdata/class/virtual.carbon

@@ -57,6 +57,23 @@ fn Fn() {
   var u: Base = {.m = 3};
 }
 
+// --- member_brace_init.carbon
+
+library "[[@TEST_NAME]]";
+
+base class Base {
+  virtual fn F[self: Self]();
+}
+
+class Derived {
+  extend base: Base;
+}
+
+fn Use() {
+  var v : Derived = {.base = {}};
+}
+
+
 // CHECK:STDOUT: ; ModuleID = 'classes.carbon'
 // CHECK:STDOUT: source_filename = "classes.carbon"
 // CHECK:STDOUT:
@@ -186,3 +203,37 @@ fn Fn() {
 // CHECK:STDOUT: !12 = !DILocation(line: 12, column: 3, scope: !8)
 // CHECK:STDOUT: !13 = !DILocation(line: 13, column: 17, scope: !8)
 // CHECK:STDOUT: !14 = !DILocation(line: 9, column: 1, scope: !8)
+// CHECK:STDOUT: ; ModuleID = 'member_brace_init.carbon'
+// CHECK:STDOUT: source_filename = "member_brace_init.carbon"
+// CHECK:STDOUT:
+// CHECK:STDOUT: declare void @_CF.Base.Main(ptr)
+// CHECK:STDOUT:
+// CHECK:STDOUT: define void @_CUse.Main() !dbg !4 {
+// CHECK:STDOUT: entry:
+// CHECK:STDOUT:   %v.var = alloca { { ptr } }, align 8, !dbg !7
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(i64 8, ptr %v.var), !dbg !7
+// CHECK:STDOUT:   %.loc13_32.2.base = getelementptr inbounds nuw { { ptr } }, ptr %v.var, i32 0, i32 0, !dbg !8
+// CHECK:STDOUT:   %.loc13_31.2.vptr = getelementptr inbounds nuw { ptr }, ptr %.loc13_32.2.base, i32 0, i32 0, !dbg !9
+// CHECK:STDOUT:   store ptr null, ptr %.loc13_31.2.vptr, align 8, !dbg !9
+// CHECK:STDOUT:   ret void, !dbg !10
+// CHECK:STDOUT: }
+// CHECK:STDOUT:
+// CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+// CHECK:STDOUT: declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0
+// CHECK:STDOUT:
+// CHECK:STDOUT: attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
+// CHECK:STDOUT:
+// CHECK:STDOUT: !llvm.module.flags = !{!0, !1}
+// CHECK:STDOUT: !llvm.dbg.cu = !{!2}
+// CHECK:STDOUT:
+// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
+// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
+// CHECK:STDOUT: !2 = distinct !DICompileUnit(language: DW_LANG_C, file: !3, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
+// CHECK:STDOUT: !3 = !DIFile(filename: "member_brace_init.carbon", directory: "")
+// CHECK:STDOUT: !4 = distinct !DISubprogram(name: "Use", linkageName: "_CUse.Main", scope: null, file: !3, line: 12, type: !5, spFlags: DISPFlagDefinition, unit: !2)
+// CHECK:STDOUT: !5 = !DISubroutineType(types: !6)
+// CHECK:STDOUT: !6 = !{}
+// CHECK:STDOUT: !7 = !DILocation(line: 13, column: 3, scope: !4)
+// CHECK:STDOUT: !8 = !DILocation(line: 13, column: 21, scope: !4)
+// CHECK:STDOUT: !9 = !DILocation(line: 13, column: 30, scope: !4)
+// CHECK:STDOUT: !10 = !DILocation(line: 12, column: 1, scope: !4)