mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-29 10:54:57 +01:00
Some module metadata changed - because rather than linking one module with one module metadata value (eg: PIC Level 0, or unspecified) and one module with a different one (PIC level 2, in clang) - we use Clang's Module as-is, no merging required, so Clang's module metadata sticks rather than being merged with default values from Carbon. Also tweaked the name we use for Clang's module name so it matches the carbon file name. Otherwise the IR changes seem to be just reorderings - C++ interop goes first, then Carbon, rather than the other way around.
213 lines
12 KiB
Plaintext
213 lines
12 KiB
Plaintext
// 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/int.carbon
|
|
//
|
|
// AUTOUPDATE
|
|
// TIP: To test this file alone, run:
|
|
// TIP: bazel test //toolchain/testing:file_test --test_arg=--file_tests=toolchain/lower/testdata/interop/cpp/virtual_base.carbon
|
|
// TIP: To dump output, run:
|
|
// TIP: bazel run //toolchain/testing:file_test -- --dump_output --file_tests=toolchain/lower/testdata/interop/cpp/virtual_base.carbon
|
|
|
|
// --- diamond.h
|
|
|
|
struct A {
|
|
A();
|
|
int a;
|
|
};
|
|
|
|
struct B : virtual A {
|
|
B();
|
|
int b;
|
|
};
|
|
|
|
struct C : virtual A {
|
|
C();
|
|
int c;
|
|
};
|
|
|
|
struct D : B, C {
|
|
int d;
|
|
};
|
|
|
|
// Layout of D (x86_64):
|
|
//
|
|
// 0: B | 0: vptr
|
|
// 8: | 8: int B::b
|
|
// 12: (4 bytes padding)
|
|
// 16: C | 0: vptr
|
|
// 24: | 8: int C::c
|
|
// 28: int D::d
|
|
// 32: A | 0: int A::a
|
|
// 36: (4 bytes padding)
|
|
// 40: (end of D)
|
|
|
|
// --- use_diamond.carbon
|
|
|
|
library "[[@TEST_NAME]]";
|
|
|
|
import Cpp library "diamond.h";
|
|
|
|
fn Make() {
|
|
// This should construct a 40-byte object, using a construtor with a `...C1`
|
|
// mangled name for D (a complete object constructor), which should call
|
|
// constructors with `...C2` mangled names for A, B, and C (base subobject
|
|
// constructors).
|
|
var _: Cpp.D = Cpp.D.D();
|
|
}
|
|
|
|
fn AccessD(d: Cpp.D) -> i32 {
|
|
// This should read an i32 at offset 28.
|
|
return d.d;
|
|
}
|
|
|
|
// CHECK:STDOUT: ; ModuleID = 'use_diamond.carbon'
|
|
// CHECK:STDOUT: source_filename = "use_diamond.carbon"
|
|
// CHECK:STDOUT: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
|
|
// CHECK:STDOUT: target triple = "x86_64-unknown-linux-gnu"
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZN1DC1Ev = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTV1D = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTT1D = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTC1D0_1B = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTI1B = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTS1B = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTI1A = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTS1A = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTC1D16_1C = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTI1C = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTS1C = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTI1D = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: $_ZTS1D = comdat any
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: @_ZTV1D = linkonce_odr dso_local unnamed_addr constant { [3 x ptr], [3 x ptr] } { [3 x ptr] [ptr inttoptr (i64 32 to ptr), ptr null, ptr @_ZTI1D], [3 x ptr] [ptr inttoptr (i64 16 to ptr), ptr inttoptr (i64 -16 to ptr), ptr @_ZTI1D] }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTT1D = linkonce_odr dso_local unnamed_addr constant [4 x ptr] [ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [3 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3), ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr] }, ptr @_ZTC1D0_1B, i32 0, i32 0, i32 3), ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr] }, ptr @_ZTC1D16_1C, i32 0, i32 0, i32 3), ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [3 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 3)], comdat, align 8
|
|
// CHECK:STDOUT: @_ZTC1D0_1B = linkonce_odr dso_local unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr inttoptr (i64 32 to ptr), ptr null, ptr @_ZTI1B] }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTI1B = linkonce_odr dso_local constant { ptr, ptr, i32, i32, ptr, i64 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), ptr @_ZTS1B, i32 0, i32 1, ptr @_ZTI1A, i64 -6141 }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTVN10__cxxabiv121__vmi_class_type_infoE = external global [0 x ptr]
|
|
// CHECK:STDOUT: @_ZTS1B = linkonce_odr dso_local constant [3 x i8] c"1B\00", comdat, align 1
|
|
// CHECK:STDOUT: @_ZTI1A = linkonce_odr dso_local constant { ptr, ptr } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), ptr @_ZTS1A }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
|
|
// CHECK:STDOUT: @_ZTS1A = linkonce_odr dso_local constant [3 x i8] c"1A\00", comdat, align 1
|
|
// CHECK:STDOUT: @_ZTC1D16_1C = linkonce_odr dso_local unnamed_addr constant { [3 x ptr] } { [3 x ptr] [ptr inttoptr (i64 16 to ptr), ptr null, ptr @_ZTI1C] }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTI1C = linkonce_odr dso_local constant { ptr, ptr, i32, i32, ptr, i64 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), ptr @_ZTS1C, i32 0, i32 1, ptr @_ZTI1A, i64 -6141 }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTS1C = linkonce_odr dso_local constant [3 x i8] c"1C\00", comdat, align 1
|
|
// CHECK:STDOUT: @_ZTI1D = linkonce_odr dso_local constant { ptr, ptr, i32, i32, ptr, i64, ptr, i64 } { ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv121__vmi_class_type_infoE, i64 2), ptr @_ZTS1D, i32 2, i32 2, ptr @_ZTI1B, i64 2, ptr @_ZTI1C, i64 4098 }, comdat, align 8
|
|
// CHECK:STDOUT: @_ZTS1D = linkonce_odr dso_local constant [3 x i8] c"1D\00", comdat, align 1
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: ; Function Attrs: alwaysinline mustprogress uwtable
|
|
// CHECK:STDOUT: define dso_local void @_ZN1DC1Ev.carbon_thunk(ptr noundef %return) #0 {
|
|
// CHECK:STDOUT: entry:
|
|
// CHECK:STDOUT: %return.addr = alloca ptr, align 8
|
|
// CHECK:STDOUT: store ptr %return, ptr %return.addr, align 8, !tbaa !12
|
|
// CHECK:STDOUT: %0 = load ptr, ptr %return.addr, align 8, !tbaa !12
|
|
// CHECK:STDOUT: call void @_ZN1DC1Ev(ptr noundef nonnull align 8 dereferenceable(32) %0)
|
|
// CHECK:STDOUT: ret void
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: ; Function Attrs: inlinehint mustprogress uwtable
|
|
// CHECK:STDOUT: define linkonce_odr dso_local void @_ZN1DC1Ev(ptr noundef nonnull align 8 dereferenceable(32) %this) unnamed_addr #1 comdat align 2 {
|
|
// CHECK:STDOUT: entry:
|
|
// CHECK:STDOUT: %this.addr = alloca ptr, align 8
|
|
// CHECK:STDOUT: store ptr %this, ptr %this.addr, align 8, !tbaa !12
|
|
// CHECK:STDOUT: %this1 = load ptr, ptr %this.addr, align 8
|
|
// CHECK:STDOUT: %0 = getelementptr inbounds i8, ptr %this1, i64 32
|
|
// CHECK:STDOUT: call void @_ZN1AC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %0)
|
|
// CHECK:STDOUT: call void @_ZN1BC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %this1, ptr noundef getelementptr inbounds ([4 x ptr], ptr @_ZTT1D, i64 0, i64 1))
|
|
// CHECK:STDOUT: %1 = getelementptr inbounds i8, ptr %this1, i64 16
|
|
// CHECK:STDOUT: call void @_ZN1CC2Ev(ptr noundef nonnull align 8 dereferenceable(12) %1, ptr noundef getelementptr inbounds ([4 x ptr], ptr @_ZTT1D, i64 0, i64 2))
|
|
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [3 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3), ptr %this1, align 8, !tbaa !15
|
|
// CHECK:STDOUT: %add.ptr = getelementptr inbounds i8, ptr %this1, i64 16
|
|
// CHECK:STDOUT: store ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [3 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 3), ptr %add.ptr, align 8, !tbaa !15
|
|
// CHECK:STDOUT: ret void
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: ; Function Attrs: nounwind
|
|
// CHECK:STDOUT: define void @_CMake.Main() #2 !dbg !17 {
|
|
// CHECK:STDOUT: entry:
|
|
// CHECK:STDOUT: %_.var = alloca [40 x i8], align 1, !dbg !20
|
|
// CHECK:STDOUT: call void @llvm.lifetime.start.p0(ptr %_.var), !dbg !20
|
|
// CHECK:STDOUT: call void @_ZN1DC1Ev.carbon_thunk(ptr %_.var), !dbg !21
|
|
// CHECK:STDOUT: ret void, !dbg !22
|
|
// CHECK:STDOUT: }
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: ; Function Attrs: nounwind
|
|
// CHECK:STDOUT: define i32 @_CAccessD.Main(ptr %d) #2 !dbg !23 {
|
|
// CHECK:STDOUT: entry:
|
|
// CHECK:STDOUT: %.loc16_11.1.d = getelementptr inbounds nuw [40 x i8], ptr %d, i32 0, i32 28, !dbg !30
|
|
// CHECK:STDOUT: %.loc16_11.2 = load i32, ptr %.loc16_11.1.d, align 4, !dbg !30
|
|
// CHECK:STDOUT: ret i32 %.loc16_11.2, !dbg !31
|
|
// 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: declare void @_ZN1AC2Ev(ptr noundef nonnull align 4 dereferenceable(4)) unnamed_addr #4
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: declare void @_ZN1BC2Ev(ptr noundef nonnull align 8 dereferenceable(12), ptr noundef) unnamed_addr #4
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: declare void @_ZN1CC2Ev(ptr noundef nonnull align 8 dereferenceable(12), ptr noundef) unnamed_addr #4
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: ; uselistorder directives
|
|
// CHECK:STDOUT: uselistorder ptr inttoptr (i64 32 to ptr), { 1, 0 }
|
|
// CHECK:STDOUT: uselistorder ptr inttoptr (i64 16 to ptr), { 1, 0 }
|
|
// CHECK:STDOUT: uselistorder ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [3 x ptr] }, ptr @_ZTV1D, i32 0, i32 0, i32 3), { 1, 0 }
|
|
// CHECK:STDOUT: uselistorder ptr getelementptr inbounds inrange(-24, 0) ({ [3 x ptr], [3 x ptr] }, ptr @_ZTV1D, i32 0, i32 1, i32 3), { 1, 0 }
|
|
// CHECK:STDOUT: uselistorder ptr @_ZTI1D, { 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 = { inlinehint 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 #2 = { nounwind }
|
|
// CHECK:STDOUT: attributes #3 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
|
|
// CHECK:STDOUT: attributes #4 = { "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:
|
|
// CHECK:STDOUT: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}
|
|
// CHECK:STDOUT: !llvm.dbg.cu = !{!6}
|
|
// CHECK:STDOUT: !llvm.errno.tbaa = !{!8}
|
|
// CHECK:STDOUT:
|
|
// CHECK:STDOUT: !0 = !{i32 7, !"Dwarf Version", i32 5}
|
|
// CHECK:STDOUT: !1 = !{i32 2, !"Debug Info Version", i32 3}
|
|
// CHECK:STDOUT: !2 = !{i32 1, !"wchar_size", i32 4}
|
|
// CHECK:STDOUT: !3 = !{i32 8, !"PIC Level", i32 2}
|
|
// CHECK:STDOUT: !4 = !{i32 7, !"PIE Level", i32 2}
|
|
// CHECK:STDOUT: !5 = !{i32 7, !"uwtable", i32 2}
|
|
// CHECK:STDOUT: !6 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !7, producer: "carbon", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
|
|
// CHECK:STDOUT: !7 = !DIFile(filename: "use_diamond.carbon", directory: "")
|
|
// CHECK:STDOUT: !8 = !{!9, !9, i64 0}
|
|
// CHECK:STDOUT: !9 = !{!"int", !10, i64 0}
|
|
// CHECK:STDOUT: !10 = !{!"omnipotent char", !11, i64 0}
|
|
// CHECK:STDOUT: !11 = !{!"Simple C++ TBAA"}
|
|
// CHECK:STDOUT: !12 = !{!13, !13, i64 0}
|
|
// CHECK:STDOUT: !13 = !{!"p1 _ZTS1D", !14, i64 0}
|
|
// CHECK:STDOUT: !14 = !{!"any pointer", !10, i64 0}
|
|
// CHECK:STDOUT: !15 = !{!16, !16, i64 0}
|
|
// CHECK:STDOUT: !16 = !{!"vtable pointer", !11, i64 0}
|
|
// CHECK:STDOUT: !17 = distinct !DISubprogram(name: "Make", linkageName: "_CMake.Main", scope: null, file: !7, line: 6, type: !18, spFlags: DISPFlagDefinition, unit: !6)
|
|
// CHECK:STDOUT: !18 = !DISubroutineType(types: !19)
|
|
// CHECK:STDOUT: !19 = !{null}
|
|
// CHECK:STDOUT: !20 = !DILocation(line: 11, column: 3, scope: !17)
|
|
// CHECK:STDOUT: !21 = !DILocation(line: 11, column: 18, scope: !17)
|
|
// CHECK:STDOUT: !22 = !DILocation(line: 6, column: 1, scope: !17)
|
|
// CHECK:STDOUT: !23 = distinct !DISubprogram(name: "AccessD", linkageName: "_CAccessD.Main", scope: null, file: !7, line: 14, type: !24, spFlags: DISPFlagDefinition, unit: !6, retainedNodes: !28)
|
|
// CHECK:STDOUT: !24 = !DISubroutineType(types: !25)
|
|
// CHECK:STDOUT: !25 = !{!26, !27}
|
|
// CHECK:STDOUT: !26 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
|
|
// CHECK:STDOUT: !27 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 8)
|
|
// CHECK:STDOUT: !28 = !{!29}
|
|
// CHECK:STDOUT: !29 = !DILocalVariable(arg: 1, scope: !23, type: !27)
|
|
// CHECK:STDOUT: !30 = !DILocation(line: 16, column: 10, scope: !23)
|
|
// CHECK:STDOUT: !31 = !DILocation(line: 16, column: 3, scope: !23)
|