Skip to content

Commit 3adc814

Browse files
committed
[5.1] SILGen: Fix the logic of dynamic replacements for class constructors
rdar://48125765
1 parent 9599228 commit 3adc814

File tree

12 files changed

+144
-22
lines changed

12 files changed

+144
-22
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3928,6 +3928,10 @@ ERROR(dynamic_replacement_replaced_not_objc_dynamic, none,
39283928
"%0 is not marked @objc dynamic", (DeclName))
39293929
ERROR(dynamic_replacement_replacement_not_objc_dynamic, none,
39303930
"%0 is marked @objc dynamic", (DeclName))
3931+
ERROR(dynamic_replacement_replaced_constructor_is_convenience, none,
3932+
"replaced constructor %0 is marked as convenience", (DeclName))
3933+
ERROR(dynamic_replacement_replaced_constructor_is_not_convenience, none,
3934+
"replaced constructor %0 is not marked as convenience", (DeclName))
39313935

39323936
//------------------------------------------------------------------------------
39333937
// MARK: @available

include/swift/IRGen/Linking.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -894,9 +894,11 @@ class LinkEntity {
894894
}
895895

896896
static LinkEntity
897-
forDynamicallyReplaceableFunctionVariable(AbstractFunctionDecl *decl) {
897+
forDynamicallyReplaceableFunctionVariable(AbstractFunctionDecl *decl,
898+
bool isAllocator) {
898899
LinkEntity entity;
899900
entity.setForDecl(Kind::DynamicallyReplaceableFunctionVariableAST, decl);
901+
entity.SecondaryPointer = isAllocator ? decl : nullptr;
900902
return entity;
901903
}
902904

@@ -910,16 +912,20 @@ class LinkEntity {
910912
}
911913

912914
static LinkEntity
913-
forDynamicallyReplaceableFunctionKey(AbstractFunctionDecl *decl) {
915+
forDynamicallyReplaceableFunctionKey(AbstractFunctionDecl *decl,
916+
bool isAllocator) {
914917
LinkEntity entity;
915918
entity.setForDecl(Kind::DynamicallyReplaceableFunctionKeyAST, decl);
919+
entity.SecondaryPointer = isAllocator ? decl : nullptr;
916920
return entity;
917921
}
918922

919923
static LinkEntity
920-
forDynamicallyReplaceableFunctionImpl(AbstractFunctionDecl *decl) {
924+
forDynamicallyReplaceableFunctionImpl(AbstractFunctionDecl *decl,
925+
bool isAllocator) {
921926
LinkEntity entity;
922927
entity.setForDecl(Kind::DynamicallyReplaceableFunctionImpl, decl);
928+
entity.SecondaryPointer = isAllocator ? decl : nullptr;
923929
return entity;
924930
}
925931

@@ -997,6 +1003,12 @@ class LinkEntity {
9971003
assert(getKind() == Kind::SILFunction);
9981004
return LINKENTITY_GET_FIELD(Data, IsDynamicallyReplaceableImpl);
9991005
}
1006+
bool isAllocator() const {
1007+
assert(getKind() == Kind::DynamicallyReplaceableFunctionImpl ||
1008+
getKind() == Kind::DynamicallyReplaceableFunctionKeyAST ||
1009+
getKind() == Kind::DynamicallyReplaceableFunctionVariableAST);
1010+
return SecondaryPointer != nullptr;
1011+
}
10001012
bool isValueWitness() const { return getKind() == Kind::ValueWitness; }
10011013
CanType getType() const {
10021014
assert(isTypeKind(getKind()));

include/swift/SIL/SILDeclRef.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,8 @@ struct SILDeclRef {
392392

393393
bool isDynamicallyReplaceable() const;
394394

395+
bool canBeDynamicReplacement() const;
396+
395397
private:
396398
friend struct llvm::DenseMapInfo<swift::SILDeclRef>;
397399
/// Produces a SILDeclRef from an opaque value.

lib/IRGen/Linking.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ std::string LinkEntity::mangleAsString() const {
317317
assert(isa<AbstractFunctionDecl>(getDecl()));
318318
std::string Result;
319319
if (auto *Constructor = dyn_cast<ConstructorDecl>(getDecl())) {
320-
Result = mangler.mangleConstructorEntity(Constructor, true,
320+
Result = mangler.mangleConstructorEntity(Constructor, isAllocator(),
321321
/*isCurried=*/false);
322322
} else {
323323
Result = mangler.mangleEntity(getDecl(), /*isCurried=*/false);
@@ -343,8 +343,9 @@ std::string LinkEntity::mangleAsString() const {
343343
assert(isa<AbstractFunctionDecl>(getDecl()));
344344
std::string Result;
345345
if (auto *Constructor = dyn_cast<ConstructorDecl>(getDecl())) {
346-
Result = mangler.mangleConstructorEntity(Constructor, true,
347-
/*isCurried=*/false);
346+
Result =
347+
mangler.mangleConstructorEntity(Constructor, isAllocator(),
348+
/*isCurried=*/false);
348349
} else {
349350
Result = mangler.mangleEntity(getDecl(), /*isCurried=*/false);
350351
}
@@ -356,8 +357,9 @@ std::string LinkEntity::mangleAsString() const {
356357
assert(isa<AbstractFunctionDecl>(getDecl()));
357358
std::string Result;
358359
if (auto *Constructor = dyn_cast<ConstructorDecl>(getDecl())) {
359-
Result = mangler.mangleConstructorEntity(Constructor, true,
360-
/*isCurried=*/false);
360+
Result =
361+
mangler.mangleConstructorEntity(Constructor, isAllocator(),
362+
/*isCurried=*/false);
361363
} else {
362364
Result = mangler.mangleEntity(getDecl(), /*isCurried=*/false);
363365
}

lib/SIL/SILDeclRef.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1003,12 +1003,35 @@ unsigned SILDeclRef::getParameterListCount() const {
10031003
}
10041004
}
10051005

1006+
static bool isDesignatedConstructorForClass(ValueDecl *decl) {
1007+
if (auto *ctor = dyn_cast_or_null<ConstructorDecl>(decl))
1008+
if (ctor->getDeclContext()->getSelfClassDecl())
1009+
return ctor->isDesignatedInit();
1010+
return false;
1011+
}
1012+
1013+
bool SILDeclRef::canBeDynamicReplacement() const {
1014+
if (kind == SILDeclRef::Kind::Destroyer)
1015+
return false;
1016+
if (kind == SILDeclRef::Kind::Initializer)
1017+
return isDesignatedConstructorForClass(getDecl());
1018+
if (kind == SILDeclRef::Kind::Allocator)
1019+
return !isDesignatedConstructorForClass(getDecl());
1020+
return true;
1021+
}
1022+
10061023
bool SILDeclRef::isDynamicallyReplaceable() const {
10071024
if (isStoredPropertyInitializer())
10081025
return false;
10091026

1027+
// Class allocators are not dynamic replaceable.
1028+
if (kind == SILDeclRef::Kind::Allocator &&
1029+
isDesignatedConstructorForClass(getDecl()))
1030+
return false;
1031+
10101032
if (kind == SILDeclRef::Kind::Destroyer ||
1011-
kind == SILDeclRef::Kind::Initializer ||
1033+
(kind == SILDeclRef::Kind::Initializer &&
1034+
!isDesignatedConstructorForClass(getDecl())) ||
10121035
kind == SILDeclRef::Kind::GlobalAccessor) {
10131036
return false;
10141037
}

lib/SIL/SILFunctionBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ void SILFunctionBuilder::addFunctionAttributes(SILFunction *F,
8585
return;
8686
}
8787

88-
if (constant.isInitializerOrDestroyer())
88+
if (!constant.canBeDynamicReplacement())
8989
return;
9090

9191
SILDeclRef declRef(replacedDecl, constant.kind, false);

lib/Sema/TypeCheckAttr.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2312,6 +2312,22 @@ void TypeChecker::checkDynamicReplacementAttribute(ValueDecl *D) {
23122312
DeclAttributes &attrs = replacements[index]->getAttrs();
23132313
attrs.add(newAttr);
23142314
}
2315+
if (auto *CD = dyn_cast<ConstructorDecl>(D)) {
2316+
auto *attr = CD->getAttrs().getAttribute<DynamicReplacementAttr>();
2317+
auto replacedIsConvenienceInit =
2318+
cast<ConstructorDecl>(attr->getReplacedFunction())->isConvenienceInit();
2319+
if (replacedIsConvenienceInit &&!CD->isConvenienceInit()) {
2320+
diagnose(attr->getLocation(),
2321+
diag::dynamic_replacement_replaced_constructor_is_convenience,
2322+
attr->getReplacedFunctionName());
2323+
} else if (!replacedIsConvenienceInit && CD->isConvenienceInit()) {
2324+
diagnose(
2325+
attr->getLocation(),
2326+
diag::dynamic_replacement_replaced_constructor_is_not_convenience,
2327+
attr->getReplacedFunctionName());
2328+
}
2329+
}
2330+
23152331

23162332
// Remove the attribute on the abstract storage (we have moved it to the
23172333
// accessor decl).

lib/TBDGen/TBDGen.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,21 @@ void TBDGenVisitor::addConformances(DeclContext *DC) {
164164
}
165165
}
166166

167+
/// Determine whether dynamic replacement should be emitted for the allocator or
168+
/// the initializer given a decl.
169+
/// The rule is that structs and convenience init of classes emit a
170+
/// dynamic replacement for the allocator.
171+
/// Designated init of classes emit a dynamic replacement for the intializer.
172+
/// This is because the super class init call is emitted to the initializer and
173+
/// needs to be dynamic.
174+
static bool shouldUseAllocatorMangling(const AbstractFunctionDecl *afd) {
175+
auto constructor = dyn_cast<ConstructorDecl>(afd);
176+
if (!constructor)
177+
return false;
178+
return constructor->getParent()->getSelfClassDecl() == nullptr ||
179+
constructor->isConvenienceInit();
180+
}
181+
167182
void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
168183
// A @_silgen_name("...") function without a body only exists
169184
// to forward-declare a symbol from another library.
@@ -175,13 +190,20 @@ void TBDGenVisitor::visitAbstractFunctionDecl(AbstractFunctionDecl *AFD) {
175190

176191
// Add the global function pointer for a dynamically replaceable function.
177192
if (AFD->isNativeDynamic()) {
178-
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(AFD));
179-
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD));
180-
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionKey(AFD));
193+
bool useAllocator = shouldUseAllocatorMangling(AFD);
194+
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(
195+
AFD, useAllocator));
196+
addSymbol(
197+
LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator));
198+
addSymbol(
199+
LinkEntity::forDynamicallyReplaceableFunctionKey(AFD, useAllocator));
181200
}
182201
if (AFD->getAttrs().hasAttribute<DynamicReplacementAttr>()) {
183-
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(AFD));
184-
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD));
202+
bool useAllocator = shouldUseAllocatorMangling(AFD);
203+
addSymbol(LinkEntity::forDynamicallyReplaceableFunctionVariable(
204+
AFD, useAllocator));
205+
addSymbol(
206+
LinkEntity::forDynamicallyReplaceableFunctionImpl(AFD, useAllocator));
185207
}
186208

187209
if (AFD->getAttrs().hasAttribute<CDeclAttr>()) {

test/Interpreter/Inputs/dynamic_replacement_module.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,8 +155,7 @@ public func replacement_for_public_global_generic_func<T>(_ t: T.Type) -> String
155155

156156
extension PublicClass {
157157
@_dynamicReplacement(for: init(x:))
158-
convenience public init(y: Int) {
159-
self.init(x: y)
158+
public init(y: Int) {
160159
str = "replacement of public_class_init"
161160
}
162161

test/SILGen/dynamically_replaceable.swift

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ struct Strukt {
3838
}
3939
}
4040
}
41-
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable5KlassC1xACSi_tcfC : $@convention(method) (Int, @thick Klass.Type) -> @owned Klass
41+
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable5KlassC1xACSi_tcfc : $@convention(method) (Int, @owned Klass) -> @owned Klass
4242
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable5KlassC08dynamic_B0yyF : $@convention(method) (@guaranteed Klass) -> () {
4343
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable5KlassC08dynamic_B4_varSivg
4444
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable5KlassC08dynamic_B4_varSivs
@@ -47,6 +47,13 @@ struct Strukt {
4747
class Klass {
4848
dynamic init(x: Int) {
4949
}
50+
51+
dynamic convenience init(c: Int) {
52+
self.init(x: c)
53+
}
54+
55+
dynamic convenience init(a: Int, b: Int) {
56+
}
5057
dynamic func dynamic_replaceable() {
5158
}
5259
dynamic func dynamic_replaceable2() {
@@ -67,6 +74,15 @@ class Klass {
6774
}
6875
}
6976

77+
class SubKlass : Klass {
78+
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable8SubKlassC1xACSi_tcfc
79+
// CHECK: // dynamic_function_ref Klass.init(x:)
80+
// CHECK: [[FUN:%.*]] = dynamic_function_ref @$s23dynamically_replaceable5KlassC1xACSi_tcfc
81+
// CHECK: apply [[FUN]]
82+
dynamic override init(x: Int) {
83+
super.init(x: x)
84+
}
85+
}
7086
// CHECK-LABEL: sil hidden [dynamically_replacable] [ossa] @$s23dynamically_replaceable6globalSivg : $@convention(thin) () -> Int {
7187
dynamic var global : Int {
7288
return 1
@@ -93,12 +109,25 @@ extension Klass {
93109
dynamic_replaceable2()
94110
}
95111

96-
// CHECK-LABEL: sil hidden [dynamic_replacement_for "$s23dynamically_replaceable5KlassC1xACSi_tcfC"] [ossa] @$s23dynamically_replaceable5KlassC1yACSi_tcfC : $@convention(method) (Int, @thick Klass.Type) -> @owned Klass {
97-
// CHECK: [[FUN:%.*]] = prev_dynamic_function_ref @$s23dynamically_replaceable5KlassC1yACSi_tcfC
112+
// CHECK-LABEL: sil hidden [dynamic_replacement_for "$s23dynamically_replaceable5KlassC1cACSi_tcfC"] [ossa] @$s23dynamically_replaceable5KlassC2crACSi_tcfC : $@convention(method) (Int, @thick Klass.Type) -> @owned Klass {
113+
// CHECK: [[FUN:%.*]] = prev_dynamic_function_ref @$s23dynamically_replaceable5KlassC2crACSi_tcfC
98114
// CHECK: apply [[FUN]]({{.*}}, %1)
115+
@_dynamicReplacement(for: init(c:))
116+
convenience init(cr: Int) {
117+
self.init(c: cr + 1)
118+
}
119+
120+
// CHECK-LABEL: sil hidden [dynamic_replacement_for "$s23dynamically_replaceable5KlassC1a1bACSi_SitcfC"] [ossa] @$s23dynamically_replaceable5KlassC2ar2brACSi_SitcfC
121+
// CHECK: // dynamic_function_ref Klass.__allocating_init(c:)
122+
// CHECK: [[FUN:%.*]] = dynamic_function_ref @$s23dynamically_replaceable5KlassC1cACSi_tcfC
123+
// CHECK: apply [[FUN]]({{.*}}, %2)
124+
@_dynamicReplacement(for: init(a: b:))
125+
convenience init(ar: Int, br: Int) {
126+
self.init(c: ar + br)
127+
}
128+
99129
@_dynamicReplacement(for: init(x:))
100-
convenience init(y: Int) {
101-
self.init(x: y + 1)
130+
init(xr: Int) {
102131
}
103132

104133
// CHECK-LABEL: sil hidden [dynamic_replacement_for "$s23dynamically_replaceable5KlassC08dynamic_B4_varSivg"] [ossa] @$s23dynamically_replaceable5KlassC1rSivg : $@convention(method) (@guaranteed Klass) -> Int {

test/attr/Inputs/dynamicReplacementC.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ public extension TheReplaceables {
77
dynamic subscript (i: Int) -> Int { return 0 }
88
dynamic subscript (s: String) -> String { return "" }
99
}
10+
11+
public class K {
12+
public init(i: Int) {}
13+
public convenience init(c : Int) { self.init(i : c) }
14+
}

test/attr/dynamicReplacement.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,11 @@ extension TheReplaceables {
3838
@_dynamicReplacement(for: subscript(_:))
3939
subscript (string_string i: String) -> String { return "" }
4040
}
41+
42+
extension K {
43+
@_dynamicReplacement(for: init(i:)) // expected-error{{replaced constructor 'init(i:)' is not marked as convenience}}
44+
convenience init(ri: Int) { }
45+
46+
@_dynamicReplacement(for: init(c:)) // expected-error{{replaced constructor 'init(c:)' is marked as convenience}})
47+
init(rc: Int) { }
48+
}

0 commit comments

Comments
 (0)