Skip to content

Commit 2089618

Browse files
authored
Merge pull request #72226 from eeckstein/fix-offset-of-empty-field
IRGen: Don't let the offset of an empty field be undef.
2 parents 6e18ffe + c11408e commit 2089618

File tree

3 files changed

+74
-3
lines changed

3 files changed

+74
-3
lines changed

lib/IRGen/GenStruct.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,14 @@ namespace {
186186
Address projectFieldAddress(IRGenFunction &IGF, Address addr, SILType T,
187187
VarDecl *field) const {
188188
auto &fieldInfo = getFieldInfo(field);
189-
if (fieldInfo.isEmpty())
190-
return fieldInfo.getTypeInfo().getUndefAddress();
189+
if (fieldInfo.isEmpty()) {
190+
// For fields with empty types, we could return undef.
191+
// But if this is a struct_element_addr which is a result of an optimized
192+
// `MemoryLayout<S>.offset(of: \.field)` we cannot return undef. We have
193+
// to be consistent with `offset(of:)`, which returns 0. Therefore we
194+
// return the base address of the struct.
195+
return addr;
196+
}
191197

192198
auto offsets = asImpl().getNonFixedOffsets(IGF, T);
193199
return fieldInfo.projectAddress(IGF, addr, offsets);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift -module-name=test %s -o %t/a.out
3+
// RUN: %target-codesign %t/a.out
4+
// RUN: %target-run %t/a.out | %FileCheck %s
5+
// RUN: %target-build-swift -module-name=test -O %s -o %t/a.out
6+
// RUN: %target-codesign %t/a.out
7+
// RUN: %target-run %t/a.out | %FileCheck %s
8+
// REQUIRES: executable_test
9+
10+
11+
enum E {
12+
case A
13+
}
14+
15+
struct X {}
16+
17+
struct S {
18+
let i: Int
19+
let e: E
20+
let x: X
21+
}
22+
23+
var gg: Int? = 27
24+
25+
@inline(never)
26+
func getOffsetE() {
27+
gg = MemoryLayout<S>.offset(of: \.e)
28+
}
29+
30+
@inline(never)
31+
func getOffsetX() {
32+
gg = MemoryLayout<S>.offset(of: \.x)
33+
}
34+
35+
getOffsetE()
36+
37+
// CHECK: Optional(0)
38+
print(gg as Any)
39+
40+
gg = 27
41+
42+
getOffsetX()
43+
44+
// CHECK: Optional(0)
45+
print(gg as Any)

test/IRGen/struct_layout.sil

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend %s -module-name main -emit-ir -o - | %FileCheck -check-prefix=%target-ptrsize %s
1+
// RUN: %target-swift-frontend %s -module-name main -emit-ir -o - | %FileCheck -check-prefix=%target-ptrsize --check-prefix=CHECK %s
22

33
import Builtin
44
import Swift
@@ -32,3 +32,23 @@ struct Rdar15410780_B {
3232
struct Rdar15410780_C {
3333
var d: String?
3434
}
35+
36+
enum EmptyEnum {
37+
case A
38+
}
39+
40+
struct S {
41+
@_hasStorage let x: Int
42+
@_hasStorage let e: EmptyEnum
43+
}
44+
45+
// CHECK-LABEL: define {{.*}} @testOffsetOfEmptyType
46+
// CHECK: ret ptr null
47+
// CHECK: }
48+
sil @testOffsetOfEmptyType : $@convention(thin) () -> Builtin.RawPointer {
49+
bb0:
50+
%0 = base_addr_for_offset $*S
51+
%1 = struct_element_addr %0 : $*S, #S.e
52+
%2 = address_to_pointer %1 : $*EmptyEnum to $Builtin.RawPointer
53+
return %2 : $Builtin.RawPointer
54+
}

0 commit comments

Comments
 (0)