Skip to content

Commit 32153fa

Browse files
Merge pull request #14434 from aschwaighofer/swift-4.1-branch-sema_require_layout_generic_params
[4.1] Sema: Request the layout for generic parameters if there is a body
2 parents 6618eb5 + cbc1d20 commit 32153fa

File tree

11 files changed

+169
-1
lines changed

11 files changed

+169
-1
lines changed

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7441,6 +7441,10 @@ namespace {
74417441
if (tc.coerceParameterListToType(params, closure, fnType))
74427442
return { false, nullptr };
74437443

7444+
// Require layout of dependent types that could be used to materialize
7445+
// metadata types/conformances during IRGen.
7446+
tc.requestRequiredNominalTypeLayoutForParameters(params);
7447+
74447448
// If this is a single-expression closure, convert the expression
74457449
// in the body to the result type of the closure.
74467450
if (closure->hasSingleExpressionBody()) {

lib/Sema/TypeCheckPattern.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,25 @@ static bool validateParameterType(ParamDecl *decl, DeclContext *DC,
755755
return hadError;
756756
}
757757

758+
/// Request nominal layout for any types that could be sources of typemetadata
759+
/// or conformances.
760+
void TypeChecker::requestRequiredNominalTypeLayoutForParameters(
761+
ParameterList *PL) {
762+
for (auto param : *PL) {
763+
if (!param->hasType())
764+
continue;
765+
766+
// Generic types are sources for typemetadata and conformances. If a
767+
// parameter is of dependent type then the body of a function with said
768+
// parameter could potentially require the generic type's layout to
769+
// recover them.
770+
if (auto *nominalDecl = dyn_cast_or_null<NominalTypeDecl>(
771+
param->getType()->getAnyGeneric())) {
772+
requestNominalLayout(nominalDecl);
773+
}
774+
}
775+
}
776+
758777
/// Type check a parameter list.
759778
bool TypeChecker::typeCheckParameterList(ParameterList *PL, DeclContext *DC,
760779
TypeResolutionOptions options,

lib/Sema/TypeCheckStmt.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,9 @@ bool TypeChecker::typeCheckAbstractFunctionBody(AbstractFunctionDecl *AFD) {
13611361
if (DebugTimeFunctionBodies || WarnLongFunctionBodies)
13621362
timer.emplace(AFD, DebugTimeFunctionBodies, WarnLongFunctionBodies);
13631363

1364+
for (auto paramList : AFD->getParameterLists())
1365+
requestRequiredNominalTypeLayoutForParameters(paramList);
1366+
13641367
if (typeCheckAbstractFunctionBodyUntil(AFD, SourceLoc()))
13651368
return true;
13661369

lib/Sema/TypeChecker.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1824,11 +1824,15 @@ class TypeChecker final : public LazyResolver {
18241824

18251825
bool typeCheckCatchPattern(CatchStmt *S, DeclContext *dc);
18261826

1827+
/// Request nominal layout for any types that could be sources of typemetadata
1828+
/// or conformances.
1829+
void requestRequiredNominalTypeLayoutForParameters(ParameterList *PL);
1830+
18271831
/// Type check a parameter list.
18281832
bool typeCheckParameterList(ParameterList *PL, DeclContext *dc,
18291833
TypeResolutionOptions options,
18301834
GenericTypeResolver &resolver);
1831-
1835+
18321836
/// Coerce a pattern to the given type.
18331837
///
18341838
/// \param P The pattern, which may be modified by this coercion.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
public class Base<T> {
2+
var t: T
3+
init(_ a: T) {
4+
t = a
5+
}
6+
}
7+
8+
public class Sub<T> : Base<T> {
9+
}
10+
11+
public func requestTypeThrough<T>(closure: (Sub<T>) -> (), arg: T) {
12+
closure(Sub(arg))
13+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify -primary-file %s %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE1 %s
2+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify %s -primary-file %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE2 %s
3+
4+
// REQUIRES: CPU=x86_64
5+
6+
// The offset of the typemetadata in the class typemetadata must match.
7+
8+
// FILE1-LABEL: define internal swiftcc void @{{.*}}4test12requestType{{.*}}(%T4test3SubC*)
9+
// FILE1: entry:
10+
// FILE1: [[T1:%.*]] = bitcast %T4test3SubC* %0 to %swift.type**
11+
// FILE1: [[TYPEMETADATA:%.*]] = load %swift.type*, %swift.type** [[T1]]
12+
// FILE1: [[T2:%.*]] = bitcast %swift.type* [[TYPEMETADATA]] to %swift.type**
13+
// This offset of T needs to be the same as the offset below.
14+
// FILE1: [[T_PTR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T2]], i64 16
15+
// FILE1: [[T:%.*]] = load %swift.type*, %swift.type** [[T_PTR]]
16+
// FILE1: call %swift.type* @{{.*}}4test3SubCMa{{.*}}(%swift.type* [[T]])
17+
18+
public func requestType2<T>(x: T) {
19+
requestTypeThrough(closure: { x in print(x) }, arg: x)
20+
}
21+
// FILE2-LABEL: define private %swift.type* @create_generic_metadata_Sub(%swift.type_pattern*, i8**)
22+
// FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type**
23+
// FILE2: [[T:%.*]] = load %swift.type*, %swift.type** %2
24+
// FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata
25+
// FILE2: [[ADDR:%.*]] = bitcast %swift.type* [[CLASSMETADATA]] to i8**
26+
// This offset of T here needs to be the same as the offset above.
27+
// FILE2: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds i8*, i8** [[ADDR]], i32 16
28+
// FILE2: [[T2:%.*]] = bitcast %swift.type* [[T]] to i8*
29+
// FILE2: store i8* [[T2]], i8** [[T_IN_CLASSMETADATA]]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify -primary-file %s %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE1 %s
2+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify %s -primary-file %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE2 %s
3+
4+
// REQUIRES: CPU=x86_64
5+
6+
// The offset of the typemetadata in the class typemetadata must match.
7+
8+
// FILE1: define hidden swiftcc i64 @_T04test12AccessorTestCSiAA3SubCyxGcluig(%T4test3SubC*, %T4test12AccessorTestC* swiftself)
9+
// FILE1: [[T1:%.*]] = bitcast %T4test3SubC* %0 to %swift.type**
10+
// FILE1: [[TYPEMETADATA:%.*]] = load %swift.type*, %swift.type** [[T1]]
11+
// FILE1: [[T2:%.*]] = bitcast %swift.type* [[TYPEMETADATA]] to %swift.type**
12+
// This offset must match the offset below.
13+
// FILE1: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T2]], i64 16
14+
// FILE1: [[T:%.*]] = load %swift.type*, %swift.type** [[T_IN_CLASSMETADATA]]
15+
// FILE1: call %swift.type* @swift_getMetatypeMetadata(%swift.type* [[T]])
16+
public class AccessorTest {
17+
subscript<T>(_ a: Sub<T>) -> Int {
18+
get {
19+
print(T.self)
20+
return 1
21+
}
22+
}
23+
}
24+
25+
// FILE2-LABEL: define private %swift.type* @create_generic_metadata_Sub(%swift.type_pattern*, i8**)
26+
// FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type**
27+
// FILE2: [[T:%.*]] = load %swift.type*, %swift.type** %2
28+
// FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata
29+
// FILE2: [[ADDR:%.*]] = bitcast %swift.type* [[CLASSMETADATA]] to i8**
30+
// This offset must match the offset above.
31+
// FILE2: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds i8*, i8** [[ADDR]], i32 16
32+
// FILE2: [[T2:%.*]] = bitcast %swift.type* [[T]] to i8*
33+
// FILE2: store i8* [[T2]], i8** [[T_IN_CLASSMETADATA]]
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify -primary-file %s %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE1 %s
2+
// RUN: %target-swift-frontend -module-name test -emit-ir -verify %s -primary-file %S/Inputs/require-layout-generic-class.swift | %FileCheck --check-prefix=FILE2 %s
3+
4+
// REQUIRES: CPU=x86_64
5+
6+
// The offset of the typemetadata in the class typemetadata must match.
7+
8+
// FILE1-LABEL: define{{.*}} swiftcc void @{{.*}}4test11requestType{{.*}}(%T4test3SubC*)
9+
// FILE1: [[T1:%.*]] = bitcast %T4test3SubC* %0 to %swift.type**
10+
// FILE1: [[TYPEMETADATA:%.*]] = load %swift.type*, %swift.type** [[T1]]
11+
// FILE1: [[T2:%.*]] = bitcast %swift.type* [[TYPEMETADATA]] to %swift.type**
12+
// This offset must match the offset below.
13+
// FILE1: [[T_PTR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[T2]], i64 16
14+
// FILE1: [[T:%.*]] = load %swift.type*, %swift.type** [[T_PTR]]
15+
public func requestType<T>(_ c: Sub<T>) {
16+
print(T.self)
17+
}
18+
19+
// FILE2-LABEL: define private %swift.type* @create_generic_metadata_Sub(%swift.type_pattern*, i8**)
20+
// FILE2: [[T_ADDR:%.*]] = bitcast i8** %1 to %swift.type**
21+
// FILE2: [[T:%.*]] = load %swift.type*, %swift.type** %2
22+
// FILE2: [[CLASSMETADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata
23+
// FILE2: [[ADDR:%.*]] = bitcast %swift.type* [[CLASSMETADATA]] to i8**
24+
// This offset must match the offset above.
25+
// FILE2: [[T_IN_CLASSMETADATA:%.*]] = getelementptr inbounds i8*, i8** [[ADDR]], i32 16
26+
// FILE2: [[T2:%.*]] = bitcast %swift.type* [[T]] to i8*
27+
// FILE2: store i8* [[T2]], i8** [[T_IN_CLASSMETADATA]]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/../require-layout-generic-arg.swift %S/../Inputs/require-layout-generic-class.swift %s -o %t/test
3+
// RUN: %target-run %t/test | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
func test() {
8+
requestType(Sub(1))
9+
}
10+
11+
// CHECK: Int
12+
test()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/../require-layout-generic-arg-closure.swift %S/../Inputs/require-layout-generic-class.swift %s -o %t/test
3+
// RUN: %target-run %t/test | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
func test() {
8+
requestType2(x: 1)
9+
}
10+
11+
// CHECK: test.Sub<Swift.Int>
12+
test()
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %S/../require-layout-generic-arg-subscript.swift %S/../Inputs/require-layout-generic-class.swift %s -o %t/test
3+
// RUN: %target-run %t/test | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
func test() {
8+
_ = AccessorTest()[Sub(1)]
9+
}
10+
11+
// CHECK: Int
12+
test()

0 commit comments

Comments
 (0)