فهرست منبع

fix: reject {} initialization for non-aggregate C++ classes (#6675)

## Summary

Fixes the toolchain incorrectly allowing `{}` initialization for
non-aggregate C++ classes.

## Problem

When importing an empty C++ class, the toolchain was treating it as a
Carbon empty struct, which allowed initialization from `{}`. This is
incorrect for non-aggregate classes (e.g., those with user-declared
constructors).

```carbon
import Cpp inline '''
struct X { X(); };  // non-aggregate (has user-declared constructor)
''';

fn Make() {
  var x: Cpp.X = {};  // incorrectly accepted, should be rejected
}
```

## Solution

Added a check for `clang_def->isAggregate()` in `ImportClassObjectRepr`
so that only aggregate classes get the empty struct representation.

**Before:**
```cpp
if (clang_def->isEmpty() && !clang_def->getNumBases()) {
```

**After:**
```cpp
if (clang_def->isEmpty() && !clang_def->getNumBases() &&
    clang_def->isAggregate()) {
```

## Testing

Added test file
`toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon`
with:
- Non-aggregate class (`struct X { X(); }`) - should reject `{}`
initialization
- Aggregate class (`struct Y {}`) - should accept `{}` initialization

Note: I couldn't run tests locally due to clang version requirements
(needs >= 19, have 17). The CI should validate the changes.

Closes #6669

---------

Co-authored-by: Richard Smith <richard@metafoo.co.uk>
little Kitchen 2 ماه پیش
والد
کامیت
8edd5eb9a1

+ 7 - 4
toolchain/check/cpp/import.cpp

@@ -429,11 +429,14 @@ static auto ImportClassObjectRepr(Context& context, SemIR::ClassId class_id,
     return SemIR::ErrorInst::TypeInstId;
   }
 
-  // For now, if the class is empty, produce an empty struct as the object
-  // representation. This allows our tests to continue to pass while we don't
-  // properly support initializing imported C++ classes.
+  // For now, if the class is empty and an aggregate, produce an empty struct as
+  // the object representation. This allows our tests to continue to pass while
+  // we don't properly support initializing imported C++ classes. We only do
+  // this for aggregates so that non-aggregate classes are not incorrectly
+  // initializable from `{}`.
   // TODO: Remove this.
-  if (clang_def->isEmpty() && !clang_def->getNumBases()) {
+  if (clang_def->isEmpty() && !clang_def->getNumBases() &&
+      clang_def->isAggregate()) {
     return context.types().GetAsTypeInstId(AddInst(
         context,
         MakeImportedLocIdAndInst(

+ 60 - 0
toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon

@@ -0,0 +1,60 @@
+// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+// INCLUDE-FILE: toolchain/testing/testdata/min_prelude/primitives.carbon
+// EXTRA-ARGS: --target=x86_64-linux-gnu --clang-arg=-std=c++20
+//
+// AUTOUPDATE
+// TIP: To test this file alone, run:
+// TIP:   bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon
+// TIP: To dump output, run:
+// TIP:   bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/check/testdata/interop/cpp/class/non_aggregate_init.carbon
+
+// ============================================================================
+// Non-aggregate class should not be initializable from {}
+// ============================================================================
+
+// --- non_aggregate.h
+
+// A class with a user-declared constructor is not an aggregate.
+struct X {
+  X();
+};
+
+// --- fail_non_aggregate_init.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp library "non_aggregate.h";
+
+fn Make() {
+  // CHECK:STDERR: fail_non_aggregate_init.carbon:[[@LINE+7]]:3: error: cannot implicitly convert expression of type `{}` to `Cpp.X` [ConversionFailure]
+  // CHECK:STDERR:   var _: Cpp.X = {};
+  // CHECK:STDERR:   ^~~~~~~~~~~~
+  // CHECK:STDERR: fail_non_aggregate_init.carbon:[[@LINE+4]]:3: note: type `{}` does not implement interface `Core.ImplicitAs(Cpp.X)` [MissingImplInMemberAccessNote]
+  // CHECK:STDERR:   var _: Cpp.X = {};
+  // CHECK:STDERR:   ^~~~~~~~~~~~
+  // CHECK:STDERR:
+  var _: Cpp.X = {};
+}
+
+// ============================================================================
+// Aggregate class should be initializable from {}
+// ============================================================================
+
+// --- aggregate.h
+
+// A class with no user-declared constructors is an aggregate.
+struct Y {};
+
+// --- aggregate_init.carbon
+
+library "[[@TEST_NAME]]";
+
+import Cpp library "aggregate.h";
+
+fn Make() {
+  // This should succeed because Y is an aggregate.
+  var _: Cpp.Y = {};
+}

+ 49 - 136
toolchain/check/testdata/interop/cpp/impls/implicit_as.carbon

@@ -252,10 +252,6 @@ fn DefaultConstructorTest() {
   //@dump-sem-ir-begin
   // OK, empty tuple maps to `{}` initializer list.
   let _: Cpp.DefaultConstructor = ();
-
-  // OK: empty struct maps to `{}` initializer list, which is an acceptable
-  // constructor call, even though a non-empty struct would not be.
-  let _: Cpp.DefaultConstructor = {};
   //@dump-sem-ir-end
 }
 
@@ -380,21 +376,6 @@ fn InitFromStruct() {
   //@dump-sem-ir-end
 }
 
-// --- todo_fail_non_aggregate_from_empty_struct.carbon
-
-library "[[@TEST_NAME]]";
-
-import Cpp library "aggregate.h";
-
-// TODO: This should be rejected; we should only support initialization from a
-// struct for an aggregate class.
-
-fn InitFromStruct() {
-  //@dump-sem-ir-begin
-  let _: Cpp.NonAggregate = {};
-  //@dump-sem-ir-end
-}
-
 // --- fail_non_aggregate_from_struct.carbon
 
 library "[[@TEST_NAME]]";
@@ -403,13 +384,26 @@ import Cpp library "aggregate.h";
 
 fn InitFromStruct() {
   //@dump-sem-ir-begin
+  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+7]]:29: error: cannot implicitly convert expression of type `{}` to `Cpp.NonAggregate` [ConversionFailure]
+  // CHECK:STDERR:   let _: Cpp.NonAggregate = {};
+  // CHECK:STDERR:                             ^~
+  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+4]]:29: note: type `{}` does not implement interface `Core.ImplicitAs(Cpp.NonAggregate)` [MissingImplInMemberAccessNote]
+  // CHECK:STDERR:   let _: Cpp.NonAggregate = {};
+  // CHECK:STDERR:                             ^~
+  // CHECK:STDERR:
   let _: Cpp.NonAggregate = {};
-  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+4]]:29: error: cannot initialize class with 0 fields from struct with 1 field [StructInitElementCountMismatch]
+  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+7]]:29: error: cannot implicitly convert expression of type `{.x: Core.IntLiteral}` to `Cpp.NonAggregate` [ConversionFailure]
+  // CHECK:STDERR:   let _: Cpp.NonAggregate = {.x = 1};
+  // CHECK:STDERR:                             ^~~~~~~~
+  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+4]]:29: note: type `{.x: Core.IntLiteral}` does not implement interface `Core.ImplicitAs(Cpp.NonAggregate)` [MissingImplInMemberAccessNote]
   // CHECK:STDERR:   let _: Cpp.NonAggregate = {.x = 1};
   // CHECK:STDERR:                             ^~~~~~~~
   // CHECK:STDERR:
   let _: Cpp.NonAggregate = {.x = 1};
-  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+4]]:29: error: cannot initialize class with 0 fields from struct with 2 fields [StructInitElementCountMismatch]
+  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+7]]:29: error: cannot implicitly convert expression of type `{.x: Core.IntLiteral, .y: Core.IntLiteral}` to `Cpp.NonAggregate` [ConversionFailure]
+  // CHECK:STDERR:   let _: Cpp.NonAggregate = {.x = 1, .y = 2};
+  // CHECK:STDERR:                             ^~~~~~~~~~~~~~~~
+  // CHECK:STDERR: fail_non_aggregate_from_struct.carbon:[[@LINE+4]]:29: note: type `{.x: Core.IntLiteral, .y: Core.IntLiteral}` does not implement interface `Core.ImplicitAs(Cpp.NonAggregate)` [MissingImplInMemberAccessNote]
   // CHECK:STDERR:   let _: Cpp.NonAggregate = {.x = 1, .y = 2};
   // CHECK:STDERR:                             ^~~~~~~~~~~~~~~~
   // CHECK:STDERR:
@@ -963,14 +957,11 @@ fn InitFromStruct() {
 // CHECK:STDOUT: constants {
 // CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
 // CHECK:STDOUT:   %DefaultConstructor: type = class_type @DefaultConstructor [concrete]
-// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %pattern_type.b66: type = pattern_type %DefaultConstructor [concrete]
 // CHECK:STDOUT:   %empty_tuple: %empty_tuple.type = tuple_value () [concrete]
 // CHECK:STDOUT:   %ptr.3f7: type = ptr_type %DefaultConstructor [concrete]
 // CHECK:STDOUT:   %DefaultConstructor__carbon_thunk.type: type = fn_type @DefaultConstructor__carbon_thunk [concrete]
 // CHECK:STDOUT:   %DefaultConstructor__carbon_thunk: %DefaultConstructor__carbon_thunk.type = struct_value () [concrete]
-// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
-// CHECK:STDOUT:   %DefaultConstructor.val: %DefaultConstructor = struct_value () [concrete]
 // CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.type: type = fn_type @DefaultConstructor.cpp_destructor [concrete]
 // CHECK:STDOUT:   %DefaultConstructor.cpp_destructor: %DefaultConstructor.cpp_destructor.type = struct_value () [concrete]
 // CHECK:STDOUT: }
@@ -991,12 +982,12 @@ fn InitFromStruct() {
 // CHECK:STDOUT: fn @DefaultConstructorTest() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %_.patt.loc9: %pattern_type.b66 = value_binding_pattern _ [concrete]
+// CHECK:STDOUT:     %_.patt: %pattern_type.b66 = value_binding_pattern _ [concrete]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc9_36.1: %empty_tuple.type = tuple_literal () [concrete = constants.%empty_tuple]
-// CHECK:STDOUT:   %.loc9_13: type = splice_block %DefaultConstructor.ref.loc9 [concrete = constants.%DefaultConstructor] {
-// CHECK:STDOUT:     %Cpp.ref.loc9: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:     %DefaultConstructor.ref.loc9: type = name_ref DefaultConstructor, imports.%DefaultConstructor.decl [concrete = constants.%DefaultConstructor]
+// CHECK:STDOUT:   %.loc9_13: type = splice_block %DefaultConstructor.ref [concrete = constants.%DefaultConstructor] {
+// CHECK:STDOUT:     %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:     %DefaultConstructor.ref: type = name_ref DefaultConstructor, imports.%DefaultConstructor.decl [concrete = constants.%DefaultConstructor]
 // CHECK:STDOUT:   }
 // CHECK:STDOUT:   %.loc9_36.2: ref %DefaultConstructor = temporary_storage
 // CHECK:STDOUT:   %addr: %ptr.3f7 = addr_of %.loc9_36.2
@@ -1005,25 +996,9 @@ fn InitFromStruct() {
 // CHECK:STDOUT:   %.loc9_36.4: init %DefaultConstructor = converted %.loc9_36.1, %.loc9_36.3
 // CHECK:STDOUT:   %.loc9_36.5: ref %DefaultConstructor = temporary %.loc9_36.2, %.loc9_36.4
 // CHECK:STDOUT:   %.loc9_36.6: %DefaultConstructor = acquire_value %.loc9_36.5
-// CHECK:STDOUT:   %_.loc9: %DefaultConstructor = value_binding _, %.loc9_36.6
-// CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %_.patt.loc13: %pattern_type.b66 = value_binding_pattern _ [concrete]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc13_36.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
-// CHECK:STDOUT:   %.loc13_13: type = splice_block %DefaultConstructor.ref.loc13 [concrete = constants.%DefaultConstructor] {
-// CHECK:STDOUT:     %Cpp.ref.loc13: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:     %DefaultConstructor.ref.loc13: type = name_ref DefaultConstructor, imports.%DefaultConstructor.decl [concrete = constants.%DefaultConstructor]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc13_36.2: ref %DefaultConstructor = temporary_storage
-// CHECK:STDOUT:   %.loc13_36.3: init %DefaultConstructor to %.loc13_36.2 = class_init () [concrete = constants.%DefaultConstructor.val]
-// CHECK:STDOUT:   %.loc13_36.4: ref %DefaultConstructor = temporary %.loc13_36.2, %.loc13_36.3
-// CHECK:STDOUT:   %.loc13_36.5: ref %DefaultConstructor = converted %.loc13_36.1, %.loc13_36.4
-// CHECK:STDOUT:   %.loc13_36.6: %DefaultConstructor = acquire_value %.loc13_36.5
-// CHECK:STDOUT:   %_.loc13: %DefaultConstructor = value_binding _, %.loc13_36.6
-// CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.bound.loc13: <bound method> = bound_method %.loc13_36.4, constants.%DefaultConstructor.cpp_destructor
-// CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.call.loc13: init %empty_tuple.type = call %DefaultConstructor.cpp_destructor.bound.loc13(%.loc13_36.4)
-// CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.bound.loc9: <bound method> = bound_method %.loc9_36.5, constants.%DefaultConstructor.cpp_destructor
-// CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.call.loc9: init %empty_tuple.type = call %DefaultConstructor.cpp_destructor.bound.loc9(%.loc9_36.5)
+// CHECK:STDOUT:   %_: %DefaultConstructor = value_binding _, %.loc9_36.6
+// CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.bound: <bound method> = bound_method %.loc9_36.5, constants.%DefaultConstructor.cpp_destructor
+// CHECK:STDOUT:   %DefaultConstructor.cpp_destructor.call: init %empty_tuple.type = call %DefaultConstructor.cpp_destructor.bound(%.loc9_36.5)
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
@@ -1493,65 +1468,19 @@ fn InitFromStruct() {
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
-// CHECK:STDOUT: --- todo_fail_non_aggregate_from_empty_struct.carbon
-// CHECK:STDOUT:
-// CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
-// CHECK:STDOUT:   %NonAggregate: type = class_type @NonAggregate [concrete]
-// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
-// CHECK:STDOUT:   %pattern_type.eac: type = pattern_type %NonAggregate [concrete]
-// CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
-// CHECK:STDOUT:   %NonAggregate.val: %NonAggregate = struct_value () [concrete]
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.type: type = fn_type @NonAggregate.cpp_destructor [concrete]
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor: %NonAggregate.cpp_destructor.type = struct_value () [concrete]
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: imports {
-// CHECK:STDOUT:   %Cpp: <namespace> = namespace file.%Cpp.import_cpp, [concrete] {
-// CHECK:STDOUT:     .NonAggregate = %NonAggregate.decl
-// CHECK:STDOUT:     import Cpp//...
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %NonAggregate.decl: type = class_decl @NonAggregate [concrete = constants.%NonAggregate] {} {}
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
-// CHECK:STDOUT: fn @InitFromStruct() {
-// CHECK:STDOUT: !entry:
-// CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %_.patt: %pattern_type.eac = value_binding_pattern _ [concrete]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc11_30.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
-// CHECK:STDOUT:   %.loc11_13: type = splice_block %NonAggregate.ref [concrete = constants.%NonAggregate] {
-// CHECK:STDOUT:     %Cpp.ref: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:     %NonAggregate.ref: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc11_30.2: ref %NonAggregate = temporary_storage
-// CHECK:STDOUT:   %.loc11_30.3: init %NonAggregate to %.loc11_30.2 = class_init () [concrete = constants.%NonAggregate.val]
-// CHECK:STDOUT:   %.loc11_30.4: ref %NonAggregate = temporary %.loc11_30.2, %.loc11_30.3
-// CHECK:STDOUT:   %.loc11_30.5: ref %NonAggregate = converted %.loc11_30.1, %.loc11_30.4
-// CHECK:STDOUT:   %.loc11_30.6: %NonAggregate = acquire_value %.loc11_30.5
-// CHECK:STDOUT:   %_: %NonAggregate = value_binding _, %.loc11_30.6
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.bound: <bound method> = bound_method %.loc11_30.4, constants.%NonAggregate.cpp_destructor
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.call: init %empty_tuple.type = call %NonAggregate.cpp_destructor.bound(%.loc11_30.4)
-// CHECK:STDOUT:   <elided>
-// CHECK:STDOUT: }
-// CHECK:STDOUT:
 // CHECK:STDOUT: --- fail_non_aggregate_from_struct.carbon
 // CHECK:STDOUT:
 // CHECK:STDOUT: constants {
-// CHECK:STDOUT:   %empty_tuple.type: type = tuple_type () [concrete]
 // CHECK:STDOUT:   %NonAggregate: type = class_type @NonAggregate [concrete]
-// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %pattern_type.eac: type = pattern_type %NonAggregate [concrete]
+// CHECK:STDOUT:   %empty_struct_type: type = struct_type {} [concrete]
 // CHECK:STDOUT:   %empty_struct: %empty_struct_type = struct_value () [concrete]
-// CHECK:STDOUT:   %NonAggregate.val: %NonAggregate = struct_value () [concrete]
 // CHECK:STDOUT:   %int_1: Core.IntLiteral = int_value 1 [concrete]
 // CHECK:STDOUT:   %struct_type.x: type = struct_type {.x: Core.IntLiteral} [concrete]
 // CHECK:STDOUT:   %struct.147: %struct_type.x = struct_value (%int_1) [concrete]
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete]
 // CHECK:STDOUT:   %struct_type.x.y: type = struct_type {.x: Core.IntLiteral, .y: Core.IntLiteral} [concrete]
 // CHECK:STDOUT:   %struct.004: %struct_type.x.y = struct_value (%int_1, %int_2) [concrete]
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.type: type = fn_type @NonAggregate.cpp_destructor [concrete]
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor: %NonAggregate.cpp_destructor.type = struct_value () [concrete]
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: imports {
@@ -1565,54 +1494,38 @@ fn InitFromStruct() {
 // CHECK:STDOUT: fn @InitFromStruct() {
 // CHECK:STDOUT: !entry:
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %_.patt.loc8: %pattern_type.eac = value_binding_pattern _ [concrete]
+// CHECK:STDOUT:     %_.patt.loc15: %pattern_type.eac = value_binding_pattern _ [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc8_30.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
-// CHECK:STDOUT:   %.loc8_13: type = splice_block %NonAggregate.ref.loc8 [concrete = constants.%NonAggregate] {
-// CHECK:STDOUT:     %Cpp.ref.loc8: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:     %NonAggregate.ref.loc8: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
+// CHECK:STDOUT:   %.loc15_30.1: %empty_struct_type = struct_literal () [concrete = constants.%empty_struct]
+// CHECK:STDOUT:   %.loc15_13: type = splice_block %NonAggregate.ref.loc15 [concrete = constants.%NonAggregate] {
+// CHECK:STDOUT:     %Cpp.ref.loc15: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:     %NonAggregate.ref.loc15: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc8_30.2: ref %NonAggregate = temporary_storage
-// CHECK:STDOUT:   %.loc8_30.3: init %NonAggregate to %.loc8_30.2 = class_init () [concrete = constants.%NonAggregate.val]
-// CHECK:STDOUT:   %.loc8_30.4: ref %NonAggregate = temporary %.loc8_30.2, %.loc8_30.3
-// CHECK:STDOUT:   %.loc8_30.5: ref %NonAggregate = converted %.loc8_30.1, %.loc8_30.4
-// CHECK:STDOUT:   %.loc8_30.6: %NonAggregate = acquire_value %.loc8_30.5
-// CHECK:STDOUT:   %_.loc8: %NonAggregate = value_binding _, %.loc8_30.6
+// CHECK:STDOUT:   %.loc15_30.2: %NonAggregate = converted %.loc15_30.1, <error> [concrete = <error>]
+// CHECK:STDOUT:   %_.loc15: %NonAggregate = value_binding _, <error> [concrete = <error>]
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %_.patt.loc13: %pattern_type.eac = value_binding_pattern _ [concrete]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %int_1.loc13: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
-// CHECK:STDOUT:   %.loc13_36.1: %struct_type.x = struct_literal (%int_1.loc13) [concrete = constants.%struct.147]
-// CHECK:STDOUT:   %.loc13_13: type = splice_block %NonAggregate.ref.loc13 [concrete = constants.%NonAggregate] {
-// CHECK:STDOUT:     %Cpp.ref.loc13: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:     %NonAggregate.ref.loc13: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc13_36.2: ref %NonAggregate = temporary_storage
-// CHECK:STDOUT:   %.loc13_36.3: ref %NonAggregate = temporary %.loc13_36.2, <error>
-// CHECK:STDOUT:   %.loc13_36.4: ref %NonAggregate = converted %.loc13_36.1, %.loc13_36.3
-// CHECK:STDOUT:   %.loc13_36.5: %NonAggregate = acquire_value %.loc13_36.4
-// CHECK:STDOUT:   %_.loc13: %NonAggregate = value_binding _, %.loc13_36.5
+// CHECK:STDOUT:     %_.patt.loc23: %pattern_type.eac = value_binding_pattern _ [concrete]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %int_1.loc23: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
+// CHECK:STDOUT:   %.loc23_36.1: %struct_type.x = struct_literal (%int_1.loc23) [concrete = constants.%struct.147]
+// CHECK:STDOUT:   %.loc23_13: type = splice_block %NonAggregate.ref.loc23 [concrete = constants.%NonAggregate] {
+// CHECK:STDOUT:     %Cpp.ref.loc23: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:     %NonAggregate.ref.loc23: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc23_36.2: %NonAggregate = converted %.loc23_36.1, <error> [concrete = <error>]
+// CHECK:STDOUT:   %_.loc23: %NonAggregate = value_binding _, <error> [concrete = <error>]
 // CHECK:STDOUT:   name_binding_decl {
-// CHECK:STDOUT:     %_.patt.loc18: %pattern_type.eac = value_binding_pattern _ [concrete]
+// CHECK:STDOUT:     %_.patt.loc31: %pattern_type.eac = value_binding_pattern _ [concrete]
 // CHECK:STDOUT:   }
-// CHECK:STDOUT:   %int_1.loc18: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
+// CHECK:STDOUT:   %int_1.loc31: Core.IntLiteral = int_value 1 [concrete = constants.%int_1]
 // CHECK:STDOUT:   %int_2: Core.IntLiteral = int_value 2 [concrete = constants.%int_2]
-// CHECK:STDOUT:   %.loc18_44.1: %struct_type.x.y = struct_literal (%int_1.loc18, %int_2) [concrete = constants.%struct.004]
-// CHECK:STDOUT:   %.loc18_13: type = splice_block %NonAggregate.ref.loc18 [concrete = constants.%NonAggregate] {
-// CHECK:STDOUT:     %Cpp.ref.loc18: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
-// CHECK:STDOUT:     %NonAggregate.ref.loc18: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
-// CHECK:STDOUT:   }
-// CHECK:STDOUT:   %.loc18_44.2: ref %NonAggregate = temporary_storage
-// CHECK:STDOUT:   %.loc18_44.3: ref %NonAggregate = temporary %.loc18_44.2, <error>
-// CHECK:STDOUT:   %.loc18_44.4: ref %NonAggregate = converted %.loc18_44.1, %.loc18_44.3
-// CHECK:STDOUT:   %.loc18_44.5: %NonAggregate = acquire_value %.loc18_44.4
-// CHECK:STDOUT:   %_.loc18: %NonAggregate = value_binding _, %.loc18_44.5
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.bound.loc18: <bound method> = bound_method %.loc18_44.3, constants.%NonAggregate.cpp_destructor
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.call.loc18: init %empty_tuple.type = call %NonAggregate.cpp_destructor.bound.loc18(%.loc18_44.3)
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.bound.loc13: <bound method> = bound_method %.loc13_36.3, constants.%NonAggregate.cpp_destructor
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.call.loc13: init %empty_tuple.type = call %NonAggregate.cpp_destructor.bound.loc13(%.loc13_36.3)
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.bound.loc8: <bound method> = bound_method %.loc8_30.4, constants.%NonAggregate.cpp_destructor
-// CHECK:STDOUT:   %NonAggregate.cpp_destructor.call.loc8: init %empty_tuple.type = call %NonAggregate.cpp_destructor.bound.loc8(%.loc8_30.4)
+// CHECK:STDOUT:   %.loc31_44.1: %struct_type.x.y = struct_literal (%int_1.loc31, %int_2) [concrete = constants.%struct.004]
+// CHECK:STDOUT:   %.loc31_13: type = splice_block %NonAggregate.ref.loc31 [concrete = constants.%NonAggregate] {
+// CHECK:STDOUT:     %Cpp.ref.loc31: <namespace> = name_ref Cpp, imports.%Cpp [concrete = imports.%Cpp]
+// CHECK:STDOUT:     %NonAggregate.ref.loc31: type = name_ref NonAggregate, imports.%NonAggregate.decl [concrete = constants.%NonAggregate]
+// CHECK:STDOUT:   }
+// CHECK:STDOUT:   %.loc31_44.2: %NonAggregate = converted %.loc31_44.1, <error> [concrete = <error>]
+// CHECK:STDOUT:   %_.loc31: %NonAggregate = value_binding _, <error> [concrete = <error>]
 // CHECK:STDOUT:   <elided>
 // CHECK:STDOUT: }
 // CHECK:STDOUT:

+ 57 - 68
toolchain/lower/testdata/interop/cpp/constructor.carbon

@@ -107,7 +107,6 @@ import Cpp library "multi_argument.h";
 fn Zero() {
   let _: Cpp.C = Cpp.C.C();
   let _: Cpp.C = ();
-  let _: Cpp.C = {};
 }
 
 fn One() {
@@ -417,8 +416,6 @@ fn Four() {
 // CHECK:STDOUT:
 // CHECK:STDOUT: $_ZN1CC2Eiiii = comdat any
 // CHECK:STDOUT:
-// CHECK:STDOUT: @C.val.loc9_19.3 = internal constant {} zeroinitializer
-// CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
 // CHECK:STDOUT: define dso_local void @_ZN1CC1Ev.carbon_thunk(ptr noundef %return) #0 {
 // CHECK:STDOUT: entry:
@@ -632,87 +629,80 @@ fn Four() {
 // CHECK:STDOUT: ; Function Attrs: nounwind
 // CHECK:STDOUT: define void @_CZero.Main() #2 !dbg !15 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %.loc7_26.1.temp = alloca {}, align 8, !dbg !18
-// CHECK:STDOUT:   %.loc8_19.2.temp = alloca {}, align 8, !dbg !19
-// CHECK:STDOUT:   %.loc9_19.2.temp = alloca {}, align 8, !dbg !20
+// CHECK:STDOUT:   %.loc7_26.1.temp = alloca [1 x i8], align 1, !dbg !18
+// CHECK:STDOUT:   %.loc8_19.2.temp = alloca [1 x i8], align 1, !dbg !19
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc7_26.1.temp), !dbg !18
 // CHECK:STDOUT:   call void @_ZN1CC1Ev.carbon_thunk(ptr %.loc7_26.1.temp), !dbg !18
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc8_19.2.temp), !dbg !19
 // CHECK:STDOUT:   call void @_ZN1CC1Ev.carbon_thunk_tuple(ptr %.loc8_19.2.temp), !dbg !19
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc9_19.2.temp), !dbg !20
-// CHECK:STDOUT:   call void @llvm.memcpy.p0.p0.i64(ptr align 1 %.loc9_19.2.temp, ptr align 1 @C.val.loc9_19.3, i64 0, i1 false), !dbg !20
-// CHECK:STDOUT:   ret void, !dbg !21
+// CHECK:STDOUT:   ret void, !dbg !20
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: nounwind
-// CHECK:STDOUT: define void @_COne.Main() #2 !dbg !22 {
+// CHECK:STDOUT: define void @_COne.Main() #2 !dbg !21 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %.loc13_27.1.temp = alloca {}, align 8, !dbg !23
-// CHECK:STDOUT:   %.loc14_18.1.temp = alloca {}, align 8, !dbg !24
-// CHECK:STDOUT:   %.loc15_21.2.temp = alloca {}, align 8, !dbg !25
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc13_27.1.temp), !dbg !23
-// CHECK:STDOUT:   call void @_ZN1CC1Ei.carbon_thunk(i32 1, ptr %.loc13_27.1.temp), !dbg !23
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc14_18.1.temp), !dbg !24
-// CHECK:STDOUT:   call void @_ZN1CC1Ei.carbon_thunk(i32 2, ptr %.loc14_18.1.temp), !dbg !24
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc15_21.2.temp), !dbg !25
-// CHECK:STDOUT:   call void @_ZN1CC1Ei.carbon_thunk_tuple(i32 3, ptr %.loc15_21.2.temp), !dbg !25
-// CHECK:STDOUT:   ret void, !dbg !26
+// CHECK:STDOUT:   %.loc12_27.1.temp = alloca [1 x i8], align 1, !dbg !22
+// CHECK:STDOUT:   %.loc13_18.1.temp = alloca [1 x i8], align 1, !dbg !23
+// CHECK:STDOUT:   %.loc14_21.2.temp = alloca [1 x i8], align 1, !dbg !24
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc12_27.1.temp), !dbg !22
+// CHECK:STDOUT:   call void @_ZN1CC1Ei.carbon_thunk(i32 1, ptr %.loc12_27.1.temp), !dbg !22
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc13_18.1.temp), !dbg !23
+// CHECK:STDOUT:   call void @_ZN1CC1Ei.carbon_thunk(i32 2, ptr %.loc13_18.1.temp), !dbg !23
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc14_21.2.temp), !dbg !24
+// CHECK:STDOUT:   call void @_ZN1CC1Ei.carbon_thunk_tuple(i32 3, ptr %.loc14_21.2.temp), !dbg !24
+// CHECK:STDOUT:   ret void, !dbg !25
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: nounwind
-// CHECK:STDOUT: define void @_CTwo.Main() #2 !dbg !27 {
+// CHECK:STDOUT: define void @_CTwo.Main() #2 !dbg !26 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %.loc19_30.1.temp = alloca {}, align 8, !dbg !28
-// CHECK:STDOUT:   %.loc20_23.2.temp = alloca {}, align 8, !dbg !29
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc19_30.1.temp), !dbg !28
-// CHECK:STDOUT:   call void @_ZN1CC1Eii.carbon_thunk(i32 1, i32 2, ptr %.loc19_30.1.temp), !dbg !28
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc20_23.2.temp), !dbg !29
-// CHECK:STDOUT:   call void @_ZN1CC1Eii.carbon_thunk_tuple(i32 3, i32 4, ptr %.loc20_23.2.temp), !dbg !29
-// CHECK:STDOUT:   ret void, !dbg !30
+// CHECK:STDOUT:   %.loc18_30.1.temp = alloca [1 x i8], align 1, !dbg !27
+// CHECK:STDOUT:   %.loc19_23.2.temp = alloca [1 x i8], align 1, !dbg !28
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc18_30.1.temp), !dbg !27
+// CHECK:STDOUT:   call void @_ZN1CC1Eii.carbon_thunk(i32 1, i32 2, ptr %.loc18_30.1.temp), !dbg !27
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc19_23.2.temp), !dbg !28
+// CHECK:STDOUT:   call void @_ZN1CC1Eii.carbon_thunk_tuple(i32 3, i32 4, ptr %.loc19_23.2.temp), !dbg !28
+// CHECK:STDOUT:   ret void, !dbg !29
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: nounwind
-// CHECK:STDOUT: define void @_CThree.Main() #2 !dbg !31 {
+// CHECK:STDOUT: define void @_CThree.Main() #2 !dbg !30 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %.loc24_33.1.temp = alloca {}, align 8, !dbg !32
-// CHECK:STDOUT:   %.loc25_26.2.temp = alloca {}, align 8, !dbg !33
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc24_33.1.temp), !dbg !32
-// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk3(i32 1, i32 2, i32 3, ptr %.loc24_33.1.temp), !dbg !32
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc25_26.2.temp), !dbg !33
-// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk_tuple3(i32 4, i32 5, i32 6, ptr %.loc25_26.2.temp), !dbg !33
-// CHECK:STDOUT:   ret void, !dbg !34
+// CHECK:STDOUT:   %.loc23_33.1.temp = alloca [1 x i8], align 1, !dbg !31
+// CHECK:STDOUT:   %.loc24_26.2.temp = alloca [1 x i8], align 1, !dbg !32
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc23_33.1.temp), !dbg !31
+// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk3(i32 1, i32 2, i32 3, ptr %.loc23_33.1.temp), !dbg !31
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc24_26.2.temp), !dbg !32
+// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk_tuple3(i32 4, i32 5, i32 6, ptr %.loc24_26.2.temp), !dbg !32
+// CHECK:STDOUT:   ret void, !dbg !33
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: nounwind
-// CHECK:STDOUT: define void @_CFour.Main() #2 !dbg !35 {
+// CHECK:STDOUT: define void @_CFour.Main() #2 !dbg !34 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %.loc29_36.1.temp = alloca {}, align 8, !dbg !36
-// CHECK:STDOUT:   %.loc30_29.2.temp = alloca {}, align 8, !dbg !37
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc29_36.1.temp), !dbg !36
-// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk(i32 1, i32 2, i32 3, i32 4, ptr %.loc29_36.1.temp), !dbg !36
-// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc30_29.2.temp), !dbg !37
-// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk_tuple(i32 5, i32 6, i32 7, i32 8, ptr %.loc30_29.2.temp), !dbg !37
-// CHECK:STDOUT:   ret void, !dbg !38
+// CHECK:STDOUT:   %.loc28_36.1.temp = alloca [1 x i8], align 1, !dbg !35
+// CHECK:STDOUT:   %.loc29_29.2.temp = alloca [1 x i8], align 1, !dbg !36
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc28_36.1.temp), !dbg !35
+// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk(i32 1, i32 2, i32 3, i32 4, ptr %.loc28_36.1.temp), !dbg !35
+// CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc29_29.2.temp), !dbg !36
+// CHECK:STDOUT:   call void @_ZN1CC1Eiiii.carbon_thunk_tuple(i32 5, i32 6, i32 7, i32 8, ptr %.loc29_29.2.temp), !dbg !36
+// CHECK:STDOUT:   ret void, !dbg !37
 // CHECK:STDOUT: }
 // CHECK:STDOUT:
 // CHECK:STDOUT: ; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
 // CHECK:STDOUT: declare void @llvm.lifetime.start.p0(ptr captures(none)) #3
 // CHECK:STDOUT:
-// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
-// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #4
-// CHECK:STDOUT:
 // CHECK:STDOUT: ; uselistorder directives
 // CHECK:STDOUT: uselistorder ptr @_ZN1CC2Ev, { 1, 0 }
 // CHECK:STDOUT: uselistorder ptr @_ZN1CC2Ei, { 1, 0 }
 // CHECK:STDOUT: uselistorder ptr @_ZN1CC2Eii, { 1, 0 }
 // CHECK:STDOUT: uselistorder ptr @_ZN1CC2Eiiii, { 3, 2, 1, 0 }
-// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }
+// CHECK:STDOUT: uselistorder ptr @llvm.lifetime.start.p0, { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }
 // CHECK:STDOUT:
 // CHECK:STDOUT: attributes #0 = { alwaysinline mustprogress uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
 // CHECK:STDOUT: attributes #1 = { mustprogress nounwind uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
 // CHECK:STDOUT: attributes #2 = { nounwind }
 // CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
-// CHECK:STDOUT: attributes #4 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
 // CHECK:STDOUT:
 // CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
 // CHECK:STDOUT: !llvm.dbg.cu = !{!6}
@@ -738,22 +728,21 @@ fn Four() {
 // CHECK:STDOUT: !17 = !{null}
 // CHECK:STDOUT: !18 = !DILocation(line: 7, column: 18, scope: !15)
 // CHECK:STDOUT: !19 = !DILocation(line: 8, column: 18, scope: !15)
-// CHECK:STDOUT: !20 = !DILocation(line: 9, column: 18, scope: !15)
-// CHECK:STDOUT: !21 = !DILocation(line: 6, column: 1, scope: !15)
-// CHECK:STDOUT: !22 = distinct !DISubprogram(name: "One", linkageName: "_COne.Main", scope: null, file: !7, line: 12, type: !16, spFlags: DISPFlagDefinition, unit: !6)
-// CHECK:STDOUT: !23 = !DILocation(line: 13, column: 18, scope: !22)
-// CHECK:STDOUT: !24 = !DILocation(line: 14, column: 18, scope: !22)
-// CHECK:STDOUT: !25 = !DILocation(line: 15, column: 18, scope: !22)
-// CHECK:STDOUT: !26 = !DILocation(line: 12, column: 1, scope: !22)
-// CHECK:STDOUT: !27 = distinct !DISubprogram(name: "Two", linkageName: "_CTwo.Main", scope: null, file: !7, line: 18, type: !16, spFlags: DISPFlagDefinition, unit: !6)
-// CHECK:STDOUT: !28 = !DILocation(line: 19, column: 18, scope: !27)
-// CHECK:STDOUT: !29 = !DILocation(line: 20, column: 18, scope: !27)
-// CHECK:STDOUT: !30 = !DILocation(line: 18, column: 1, scope: !27)
-// CHECK:STDOUT: !31 = distinct !DISubprogram(name: "Three", linkageName: "_CThree.Main", scope: null, file: !7, line: 23, type: !16, spFlags: DISPFlagDefinition, unit: !6)
-// CHECK:STDOUT: !32 = !DILocation(line: 24, column: 18, scope: !31)
-// CHECK:STDOUT: !33 = !DILocation(line: 25, column: 18, scope: !31)
-// CHECK:STDOUT: !34 = !DILocation(line: 23, column: 1, scope: !31)
-// CHECK:STDOUT: !35 = distinct !DISubprogram(name: "Four", linkageName: "_CFour.Main", scope: null, file: !7, line: 28, type: !16, spFlags: DISPFlagDefinition, unit: !6)
-// CHECK:STDOUT: !36 = !DILocation(line: 29, column: 18, scope: !35)
-// CHECK:STDOUT: !37 = !DILocation(line: 30, column: 18, scope: !35)
-// CHECK:STDOUT: !38 = !DILocation(line: 28, column: 1, scope: !35)
+// CHECK:STDOUT: !20 = !DILocation(line: 6, column: 1, scope: !15)
+// CHECK:STDOUT: !21 = distinct !DISubprogram(name: "One", linkageName: "_COne.Main", scope: null, file: !7, line: 11, type: !16, spFlags: DISPFlagDefinition, unit: !6)
+// CHECK:STDOUT: !22 = !DILocation(line: 12, column: 18, scope: !21)
+// CHECK:STDOUT: !23 = !DILocation(line: 13, column: 18, scope: !21)
+// CHECK:STDOUT: !24 = !DILocation(line: 14, column: 18, scope: !21)
+// CHECK:STDOUT: !25 = !DILocation(line: 11, column: 1, scope: !21)
+// CHECK:STDOUT: !26 = distinct !DISubprogram(name: "Two", linkageName: "_CTwo.Main", scope: null, file: !7, line: 17, type: !16, spFlags: DISPFlagDefinition, unit: !6)
+// CHECK:STDOUT: !27 = !DILocation(line: 18, column: 18, scope: !26)
+// CHECK:STDOUT: !28 = !DILocation(line: 19, column: 18, scope: !26)
+// CHECK:STDOUT: !29 = !DILocation(line: 17, column: 1, scope: !26)
+// CHECK:STDOUT: !30 = distinct !DISubprogram(name: "Three", linkageName: "_CThree.Main", scope: null, file: !7, line: 22, type: !16, spFlags: DISPFlagDefinition, unit: !6)
+// CHECK:STDOUT: !31 = !DILocation(line: 23, column: 18, scope: !30)
+// CHECK:STDOUT: !32 = !DILocation(line: 24, column: 18, scope: !30)
+// CHECK:STDOUT: !33 = !DILocation(line: 22, column: 1, scope: !30)
+// CHECK:STDOUT: !34 = distinct !DISubprogram(name: "Four", linkageName: "_CFour.Main", scope: null, file: !7, line: 27, type: !16, spFlags: DISPFlagDefinition, unit: !6)
+// CHECK:STDOUT: !35 = !DILocation(line: 28, column: 18, scope: !34)
+// CHECK:STDOUT: !36 = !DILocation(line: 29, column: 18, scope: !34)
+// CHECK:STDOUT: !37 = !DILocation(line: 27, column: 1, scope: !34)

+ 11 - 11
toolchain/lower/testdata/interop/cpp/std_initializer_list.carbon

@@ -206,7 +206,7 @@ fn InitNontrivialDtor() {
 // CHECK:STDOUT: ; Function Attrs: nounwind
 // CHECK:STDOUT: define void @_CInitVectorLike.Main() #3 !dbg !29 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %_.var = alloca {}, align 8, !dbg !30
+// CHECK:STDOUT:   %_.var = alloca [1 x i8], align 1, !dbg !30
 // CHECK:STDOUT:   %.loc18_36.2.temp = alloca [16 x i8], align 1, !dbg !31
 // CHECK:STDOUT:   %.loc18_36.4.temp = alloca [3 x i32], align 4, !dbg !31
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !30
@@ -240,19 +240,19 @@ fn InitNontrivialDtor() {
 // CHECK:STDOUT: define void @_CInitNontrivialDtor.Main() #3 !dbg !34 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %_.var = alloca [16 x i8], align 1, !dbg !35
-// CHECK:STDOUT:   %.loc23_69.17.temp = alloca [3 x {}], align 8, !dbg !36
+// CHECK:STDOUT:   %.loc23_69.17.temp = alloca [3 x [1 x i8]], align 1, !dbg !36
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !35
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc23_69.17.temp), !dbg !36
-// CHECK:STDOUT:   %.loc23_69.18.array.index = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 0, i64 0, !dbg !36
+// CHECK:STDOUT:   %.loc23_69.18.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 0, !dbg !36
 // CHECK:STDOUT:   call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.18.array.index), !dbg !36
-// CHECK:STDOUT:   %.loc23_69.16.array.index = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 0, i64 1, !dbg !36
+// CHECK:STDOUT:   %.loc23_69.16.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 1, !dbg !36
 // CHECK:STDOUT:   call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.16.array.index), !dbg !36
-// CHECK:STDOUT:   %.loc23_69.15.array.index = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 0, i64 2, !dbg !36
+// CHECK:STDOUT:   %.loc23_69.15.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 2, !dbg !36
 // CHECK:STDOUT:   call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.15.array.index), !dbg !36
 // CHECK:STDOUT:   %initializer_list.initializer_list.call.init_list.begin = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 0, !dbg !35
 // CHECK:STDOUT:   store ptr %.loc23_69.17.temp, ptr %initializer_list.initializer_list.call.init_list.begin, align 8, !dbg !35
 // CHECK:STDOUT:   %initializer_list.initializer_list.call.init_list.end = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 8, !dbg !35
-// CHECK:STDOUT:   %initializer_list.initializer_list.call.array.end = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 1, !dbg !35
+// CHECK:STDOUT:   %initializer_list.initializer_list.call.array.end = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 1, !dbg !35
 // CHECK:STDOUT:   store ptr %initializer_list.initializer_list.call.array.end, ptr %initializer_list.initializer_list.call.init_list.end, align 8, !dbg !35
 // CHECK:STDOUT:   call void @_CWithinLifetime.Main(), !dbg !37
 // CHECK:STDOUT:   ret void, !dbg !38
@@ -407,7 +407,7 @@ fn InitNontrivialDtor() {
 // CHECK:STDOUT: ; Function Attrs: nounwind
 // CHECK:STDOUT: define void @_CInitVectorLike.Main() #3 !dbg !31 {
 // CHECK:STDOUT: entry:
-// CHECK:STDOUT:   %_.var = alloca {}, align 8, !dbg !32
+// CHECK:STDOUT:   %_.var = alloca [1 x i8], align 1, !dbg !32
 // CHECK:STDOUT:   %.loc18_36.2.temp = alloca [16 x i8], align 1, !dbg !33
 // CHECK:STDOUT:   %.loc18_36.4.temp = alloca [3 x i32], align 4, !dbg !33
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !32
@@ -440,14 +440,14 @@ fn InitNontrivialDtor() {
 // CHECK:STDOUT: define void @_CInitNontrivialDtor.Main() #3 !dbg !36 {
 // CHECK:STDOUT: entry:
 // CHECK:STDOUT:   %_.var = alloca [16 x i8], align 1, !dbg !37
-// CHECK:STDOUT:   %.loc23_69.17.temp = alloca [3 x {}], align 8, !dbg !38
+// CHECK:STDOUT:   %.loc23_69.17.temp = alloca [3 x [1 x i8]], align 1, !dbg !38
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !37
 // CHECK:STDOUT:   call void @llvm.lifetime.start.p0(ptr %.loc23_69.17.temp), !dbg !38
-// CHECK:STDOUT:   %.loc23_69.18.array.index = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 0, i64 0, !dbg !38
+// CHECK:STDOUT:   %.loc23_69.18.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 0, !dbg !38
 // CHECK:STDOUT:   call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.18.array.index), !dbg !38
-// CHECK:STDOUT:   %.loc23_69.16.array.index = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 0, i64 1, !dbg !38
+// CHECK:STDOUT:   %.loc23_69.16.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 1, !dbg !38
 // CHECK:STDOUT:   call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.16.array.index), !dbg !38
-// CHECK:STDOUT:   %.loc23_69.15.array.index = getelementptr inbounds [3 x {}], ptr %.loc23_69.17.temp, i32 0, i64 2, !dbg !38
+// CHECK:STDOUT:   %.loc23_69.15.array.index = getelementptr inbounds [3 x [1 x i8]], ptr %.loc23_69.17.temp, i32 0, i64 2, !dbg !38
 // CHECK:STDOUT:   call void @_ZN15nontrivial_dtorC1Ev.carbon_thunk_tuple(ptr %.loc23_69.15.array.index), !dbg !38
 // CHECK:STDOUT:   %initializer_list.initializer_list.call.init_list.begin = getelementptr inbounds nuw [16 x i8], ptr %_.var, i32 0, i32 0, !dbg !37
 // CHECK:STDOUT:   store ptr %.loc23_69.17.temp, ptr %initializer_list.initializer_list.call.init_list.begin, align 8, !dbg !37