Skip to content

[5.0] IRGen: Empty fields do have an entry in the field offset vector #13906

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/IRGen/StructLayout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ bool StructLayoutBuilder::addField(ElementLayout &elt,
if (eltTI.isKnownEmpty(ResilienceExpansion::Maximal)) {
addEmptyElement(elt);
// If the element type is empty, it adds nothing.
NextNonFixedOffsetIndex++;
return false;
}
// TODO: consider using different layout rules.
Expand Down
34 changes: 33 additions & 1 deletion test/IRGen/generic_structs.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -primary-file %s -emit-ir | %FileCheck %s --check-prefix=CHECK-%target-ptrsize

struct A<T1, T2>
{
Expand All @@ -25,3 +25,35 @@ struct Foo<A1, A2>

struct Bar<A1, A2> {
}

public protocol Proto { }

public struct EmptyStruct {}

public struct GenericStruct<T : Proto> {
var empty: EmptyStruct = EmptyStruct()
var dummy: Int = 0
var opt: Optional<T> = nil

public init() {}
}

// CHECK-32-LABEL: define{{.*}} swiftcc void @"$S15generic_structs13GenericStructVACyxGycfC"
// CHECK-32: [[TYPE:%.*]] = call %swift.type* @"$S15generic_structs13GenericStructVMa"(%swift.type* %T, i8** %T.Proto)
// CHECK-32: [[PTR:%.*]] = bitcast %swift.type* [[TYPE]] to i32*
// CHECK-32: [[FIELDOFFSETS:%.*]] = getelementptr inbounds i32, i32* [[PTR]], i32 2
// CHECK-32: [[FIELDOFFSET:%.*]] = getelementptr inbounds i32, i32* [[FIELDOFFSETS]], i32 2
// CHECK-32: [[OFFSET:%.*]] = load i32, i32* [[FIELDOFFSET]]
// CHECK-32: [[ADDROFOPT:%.*]] = getelementptr inbounds i8, i8* {{.*}}, i32 [[OFFSET]]
// CHECK-32: [[OPTPTR:%.*]] = bitcast i8* [[ADDROFOPT]] to %TSq*
// CHECK-32: call %TSq* @"$S15generic_structsytWb3_"(%TSq* {{.*}}, %TSq* [[OPTPTR]]

// CHECK-64-LABEL: define{{.*}} swiftcc void @"$S15generic_structs13GenericStructVACyxGycfC"
// CHECK-64: [[TYPE:%.*]] = call %swift.type* @"$S15generic_structs13GenericStructVMa"(%swift.type* %T, i8** %T.Proto)
// CHECK-64: [[PTR:%.*]] = bitcast %swift.type* [[TYPE]] to i64*
// CHECK-64: [[FIELDOFFSETS:%.*]] = getelementptr inbounds i64, i64* [[PTR]], i64 2
// CHECK-64: [[FIELDOFFSET:%.*]] = getelementptr inbounds i64, i64* [[FIELDOFFSETS]], i32 2
// CHECK-64: [[OFFSET:%.*]] = load i64, i64* [[FIELDOFFSET]]
// CHECK-64: [[ADDROFOPT:%.*]] = getelementptr inbounds i8, i8* {{.*}}, i64 [[OFFSET]]
// CHECK-64: [[OPTPTR:%.*]] = bitcast i8* [[ADDROFOPT]] to %TSq*
// CHECK-64: call %TSq* @"$S15generic_structsytWb3_"(%TSq* {{.*}}, %TSq* [[OPTPTR]]
27 changes: 27 additions & 0 deletions test/Interpreter/field_offset_generic.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// RUN: %target-run-simple-swift | %FileCheck %s
// REQUIRES: executable_test

public protocol Proto { }

public struct MyImpl: Proto { }

public struct EmptyStruct {}

private struct GenericStruct<T : Proto> {
var empty: EmptyStruct = EmptyStruct()
var dummy: Int = 0
var opt: Optional<T> = nil

init() {
}
}

public func test() {
let s = GenericStruct<MyImpl>()
assert(s.dummy == 0, "Expecting dummy == 0")
assert(s.opt == nil, "Expecting opt == nil")
// CHECK: dummy: 0
print("dummy: \(s.dummy)")
}

test()