Skip to content

Commit b5edbb9

Browse files
authored
Merge pull request #2492 from swiftwasm/release/5.4
[pull] swiftwasm-release/5.4 from release/5.4
2 parents ec9824f + 3544c16 commit b5edbb9

File tree

10 files changed

+434
-313
lines changed

10 files changed

+434
-313
lines changed

include/swift/Runtime/Concurrent.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -527,13 +527,18 @@ template <class ElemTy> struct ConcurrentReadableArray {
527527

528528
storage = newStorage;
529529
Capacity = newCapacity;
530-
Elements.store(storage, std::memory_order_release);
530+
531+
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
532+
// ordered after this store. If ReaderCount is loaded first, then a new
533+
// reader could come in between that load and this store, and then we
534+
// could end up freeing the old storage pointer while it's still in use.
535+
Elements.store(storage, std::memory_order_seq_cst);
531536
}
532537

533538
new(&storage->data()[count]) ElemTy(elem);
534539
storage->Count.store(count + 1, std::memory_order_release);
535540

536-
if (ReaderCount.load(std::memory_order_acquire) == 0)
541+
if (ReaderCount.load(std::memory_order_seq_cst) == 0)
537542
deallocateFreeList();
538543
}
539544

@@ -848,7 +853,7 @@ struct ConcurrentReadableHashMap {
848853
/// Free all the arrays in the free lists if there are no active readers. If
849854
/// there are active readers, do nothing.
850855
void deallocateFreeListIfSafe() {
851-
if (ReaderCount.load(std::memory_order_acquire) == 0)
856+
if (ReaderCount.load(std::memory_order_seq_cst) == 0)
852857
FreeListNode::freeAll(&FreeList);
853858
}
854859

@@ -866,7 +871,11 @@ struct ConcurrentReadableHashMap {
866871
FreeListNode::add(&FreeList, elements);
867872
}
868873

869-
Elements.store(newElements, std::memory_order_release);
874+
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
875+
// ordered after this store. If ReaderCount is loaded first, then a new
876+
// reader could come in between that load and this store, and then we
877+
// could end up freeing the old elements pointer while it's still in use.
878+
Elements.store(newElements, std::memory_order_seq_cst);
870879
return newElements;
871880
}
872881

@@ -900,7 +909,11 @@ struct ConcurrentReadableHashMap {
900909
newIndices.storeIndexAt(nullptr, index, newI, std::memory_order_relaxed);
901910
}
902911

903-
Indices.store(newIndices.Value, std::memory_order_release);
912+
// Use seq_cst here to ensure that the subsequent load of ReaderCount is
913+
// ordered after this store. If ReaderCount is loaded first, then a new
914+
// reader could come in between that load and this store, and then we
915+
// could end up freeing the old indices pointer while it's still in use.
916+
Indices.store(newIndices.Value, std::memory_order_seq_cst);
904917

905918
if (auto *ptr = indices.pointer())
906919
FreeListNode::add(&FreeList, ptr);

include/swift/Sema/OverloadChoice.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,14 @@ class OverloadChoice {
7373
/// optional context type, turning a "Decl" kind into
7474
/// "DeclViaUnwrappedOptional".
7575
IsDeclViaUnwrappedOptional = 0x02,
76+
/// Indicates that there are viable members found on `Optional`
77+
/// type and its underlying type. And current overload choice
78+
/// is a backup one, which should be picked only if members
79+
/// found directly on `Optional` do not match.
80+
IsFallbackDeclViaUnwrappedOptional = 0x03,
7681
/// Indicates that this declaration was dynamic, turning a
7782
/// "Decl" kind into "DeclViaDynamic" kind.
78-
IsDeclViaDynamic = 0x03,
83+
IsDeclViaDynamic = 0x07,
7984
};
8085

8186
/// The base type to be used when referencing the declaration
@@ -175,17 +180,23 @@ class OverloadChoice {
175180

176181
/// Retrieve an overload choice for a declaration that was found
177182
/// by unwrapping an optional context type.
183+
///
184+
/// \param isFallback Indicates that this result should be used
185+
/// as a backup, if member found directly on `Optional` doesn't
186+
/// match.
178187
static OverloadChoice
179-
getDeclViaUnwrappedOptional(Type base, ValueDecl *value,
188+
getDeclViaUnwrappedOptional(Type base, ValueDecl *value, bool isFallback,
180189
FunctionRefKind functionRefKind) {
181190
OverloadChoice result;
182191
result.BaseAndDeclKind.setPointer(base);
183-
result.BaseAndDeclKind.setInt(IsDeclViaUnwrappedOptional);
192+
result.BaseAndDeclKind.setInt(isFallback
193+
? IsFallbackDeclViaUnwrappedOptional
194+
: IsDeclViaUnwrappedOptional);
184195
result.DeclOrKind = value;
185196
result.TheFunctionRefKind = functionRefKind;
186197
return result;
187198
}
188-
199+
189200
/// Retrieve an overload choice for a declaration that was found via
190201
/// dynamic member lookup. The `ValueDecl` is a `subscript(dynamicMember:)`
191202
/// method.
@@ -219,6 +230,7 @@ class OverloadChoice {
219230
case IsDeclViaBridge: return OverloadChoiceKind::DeclViaBridge;
220231
case IsDeclViaDynamic: return OverloadChoiceKind::DeclViaDynamic;
221232
case IsDeclViaUnwrappedOptional:
233+
case IsFallbackDeclViaUnwrappedOptional:
222234
return OverloadChoiceKind::DeclViaUnwrappedOptional;
223235
default: return OverloadChoiceKind::Decl;
224236
}
@@ -256,6 +268,12 @@ class OverloadChoice {
256268
return getKind() == OverloadChoiceKind::KeyPathDynamicMemberLookup;
257269
}
258270

271+
/// Determine whether this member is a backup in case
272+
/// members found directly on `Optional` didn't match.
273+
bool isFallbackMemberOnUnwrappedBase() const {
274+
return BaseAndDeclKind.getInt() == IsFallbackDeclViaUnwrappedOptional;
275+
}
276+
259277
/// Get the name of the overload choice.
260278
DeclName getName() const;
261279

lib/SIL/IR/TypeLowering.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,15 @@ namespace {
414414
return visitAbstractTypeParamType(type, origType, isSensitive);
415415
}
416416

417-
Type getConcreteReferenceStorageReferent(Type type) {
417+
Type getConcreteReferenceStorageReferent(Type type,
418+
AbstractionPattern origType) {
418419
if (type->isTypeParameter()) {
420+
auto genericSig = origType.getGenericSignature();
421+
if (auto concreteType = genericSig->getConcreteType(type))
422+
return concreteType;
423+
if (auto superclassType = genericSig->getSuperclassBound(type))
424+
return superclassType;
425+
assert(genericSig->requiresClass(type));
419426
return TC.Context.getAnyObjectType();
420427
}
421428

@@ -460,7 +467,7 @@ namespace {
460467
IsTypeExpansionSensitive_t isSensitive) { \
461468
auto referentType = \
462469
type->getReferentType()->lookThroughSingleOptionalType(); \
463-
auto concreteType = getConcreteReferenceStorageReferent(referentType); \
470+
auto concreteType = getConcreteReferenceStorageReferent(referentType, origType); \
464471
if (Name##StorageType::get(concreteType, TC.Context) \
465472
->isLoadable(Expansion.getResilienceExpansion())) { \
466473
return asImpl().visitLoadable##Name##StorageType(type, origType, \

lib/Sema/CSSimplify.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6666,8 +6666,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
66666666

66676667
// Local function that turns a ValueDecl into a properly configured
66686668
// OverloadChoice.
6669-
auto getOverloadChoice = [&](ValueDecl *cand, bool isBridged,
6670-
bool isUnwrappedOptional) -> OverloadChoice {
6669+
auto getOverloadChoice =
6670+
[&](ValueDecl *cand, bool isBridged, bool isUnwrappedOptional,
6671+
bool isFallbackUnwrap = false) -> OverloadChoice {
66716672
// If we're looking into an existential type, check whether this
66726673
// result was found via dynamic lookup.
66736674
if (instanceTy->isAnyObject()) {
@@ -6688,8 +6689,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
66886689
auto ovlBaseTy = MetatypeType::get(baseTy->castTo<MetatypeType>()
66896690
->getInstanceType()
66906691
->getOptionalObjectType());
6691-
return OverloadChoice::getDeclViaUnwrappedOptional(ovlBaseTy, cand,
6692-
functionRefKind);
6692+
return OverloadChoice::getDeclViaUnwrappedOptional(
6693+
ovlBaseTy, cand,
6694+
/*isFallback=*/isFallbackUnwrap, functionRefKind);
66936695
}
66946696

66956697
// While looking for subscript choices it's possible to find
@@ -6713,7 +6715,7 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
67136715

67146716
return OverloadChoice(baseTy, cand, functionRefKind);
67156717
};
6716-
6718+
67176719
// Add all results from this lookup.
67186720
for (auto result : lookup)
67196721
addChoice(getOverloadChoice(result.getValueDecl(),
@@ -6796,11 +6798,16 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
67966798
}
67976799

67986800
if (objectType->mayHaveMembers()) {
6801+
// If there are viable members directly on `Optional`, let's
6802+
// prioritize them any mark any results found on wrapped type
6803+
// as a fallback results.
6804+
bool isFallback = !result.ViableCandidates.empty();
67996805
LookupResult &optionalLookup = lookupMember(objectType, memberName);
68006806
for (auto result : optionalLookup)
68016807
addChoice(getOverloadChoice(result.getValueDecl(),
6802-
/*bridged*/false,
6803-
/*isUnwrappedOptional=*/true));
6808+
/*bridged*/ false,
6809+
/*isUnwrappedOptional=*/true,
6810+
/*isUnwrapFallback=*/isFallback));
68046811
}
68056812
}
68066813
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2798,8 +2798,7 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
27982798
increaseScore(SK_DisfavoredOverload);
27992799
}
28002800

2801-
if (choice.getKind() == OverloadChoiceKind::DeclViaUnwrappedOptional &&
2802-
locator->isLastElement<LocatorPathElt::UnresolvedMember>()) {
2801+
if (choice.isFallbackMemberOnUnwrappedBase()) {
28032802
increaseScore(SK_UnresolvedMemberViaOptional);
28042803
}
28052804
}

test/Constraints/sr13815.swift

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
// SR-13815
4+
5+
enum E {
6+
case foo(String)
7+
}
8+
9+
struct Test {
10+
var bar: E?
11+
}
12+
13+
struct S {
14+
func evaluate(_: Test) -> [Test] {
15+
return []
16+
}
17+
18+
func test(set: Set<String>) {
19+
let flattened = set.flatMap { element in
20+
evaluate(Test(bar: .foo(element)))
21+
}
22+
23+
let _: [Test] = flattened // Ok (find .`bar` after unwrap)
24+
}
25+
}

test/Interop/Cxx/static/static-member-func.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-clang -c %S/Inputs/static-member-func.cpp -I %S/Inputs -o %t/static-member-func.o -std=c++11
3-
// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-func.o -Xfrontend -enable-cxx-interop -Xcc -std=c++11
3+
// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-func.o -Xfrontend -enable-cxx-interop
44
// RUN: %target-codesign %t/statics
55
// RUN: %target-run %t/statics
66
//

test/Interop/Cxx/static/static-member-var.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-clang -c %S/Inputs/static-member-var.cpp -I %S/Inputs -o %t/static-member-var.o -std=c++11
3-
// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop -Xcc -std=c++11
3+
// RUN: %target-build-swift %s -I %S/Inputs -o %t/statics %t/static-member-var.o -Xfrontend -enable-cxx-interop
44
// RUN: %target-codesign %t/statics
55
// RUN: %target-run %t/statics
66
//
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-swift-emit-silgen %s -enable-objc-interop | %FileCheck %s
2+
3+
protocol ClassProtocol: AnyObject {}
4+
5+
class BaseClass {}
6+
7+
func makeGenericClosureWithUnknownClass<T>(t: T) where T : ClassProtocol {
8+
_ = { [unowned t] in _ = t }
9+
}
10+
11+
// CHECK-LABEL: sil private [ossa] @$s4main34makeGenericClosureWithUnknownClass1tyx_tAA0G8ProtocolRzlFyycfU_ : $@convention(thin) <T where T : ClassProtocol> (@guaranteed <τ_0_0 where τ_0_0 : ClassProtocol> { var @sil_unowned τ_0_0 } <T>) -> () {
12+
13+
func makeGenericClosureWithNativeClass1<T>(t: T) where T : BaseClass {
14+
_ = { [unowned t] in _ = t }
15+
}
16+
17+
// CHECK-LABEL: sil private [ossa] @$s4main34makeGenericClosureWithNativeClass11tyx_tAA9BaseClassCRbzlFyycfU_ : $@convention(thin) <T where T : BaseClass> (@guaranteed @sil_unowned T) -> () {
18+
19+
func makeGenericClosureWithNativeClass2<T>(t: T) where T : ClassProtocol, T : BaseClass {
20+
_ = { [unowned t] in _ = t }
21+
}
22+
23+
// CHECK-LABEL: sil private [ossa] @$s4main34makeGenericClosureWithNativeClass21tyx_tAA9BaseClassCRbzAA0I8ProtocolRzlFyycfU_ : $@convention(thin) <T where T : BaseClass, T : ClassProtocol> (@guaranteed @sil_unowned T) -> () {

0 commit comments

Comments
 (0)