Skip to content

Commit 5126044

Browse files
Merge pull request #5295 from swiftwasm/main
[pull] swiftwasm from main
2 parents 83a474c + 2e8ae40 commit 5126044

24 files changed

+528
-229
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6855,12 +6855,9 @@ ERROR(moveonly_copyable_type_that_contains_moveonly_type, none,
68556855
NOTE(moveonly_copyable_type_that_contains_moveonly_type_location, none,
68566856
"contained move-only %0 '%1.%2'",
68576857
(DescriptiveDeclKind, StringRef, StringRef))
6858-
ERROR(moveonly_cannot_conform_to_protocol, none,
6859-
"move-only %0 %1 cannot conform yet to any protocols",
6860-
(DescriptiveDeclKind, DeclName))
6861-
ERROR(moveonly_cannot_conform_to_protocol_with_name, none,
6862-
"move-only %0 %1 cannot conform to protocol %2",
6863-
(DescriptiveDeclKind, DeclName, DeclName))
6858+
ERROR(moveonly_cannot_conform_to_type, none,
6859+
"move-only %0 %1 cannot conform to %2",
6860+
(DescriptiveDeclKind, DeclName, Type))
68646861
ERROR(moveonly_non_final_class_cannot_contain_moveonly_field, none,
68656862
"non-final classes containing move only fields is not yet supported", ())
68666863

lib/AST/ProtocolConformance.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1056,6 +1056,13 @@ void NominalTypeDecl::prepareConformanceTable() const {
10561056
if (!proto)
10571057
return;
10581058

1059+
// No synthesized conformances for move-only nominals.
1060+
if (isMoveOnly()) {
1061+
// assumption is Sendable gets synthesized elsewhere.
1062+
assert(!proto->isSpecificProtocol(KnownProtocolKind::Sendable));
1063+
return;
1064+
}
1065+
10591066
if (protocols.count(proto) == 0) {
10601067
ConformanceTable->addSynthesizedConformance(
10611068
mutableThis, proto, mutableThis);

lib/Refactoring/Refactoring.cpp

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8595,6 +8595,50 @@ bool RefactoringActionExpandMacro::isApplicable(const ResolvedCursorInfo &Info,
85958595
return !getMacroExpansionBuffers(Diag.SourceMgr, Info).empty();
85968596
}
85978597

8598+
/// Given the expanded code for a particular macro, perform whitespace
8599+
/// adjustments to make the refactoring more.
8600+
static StringRef adjustMacroExpansionWhitespace(
8601+
GeneratedSourceInfo::Kind kind, StringRef expandedCode,
8602+
llvm::SmallString<64> &scratch
8603+
) {
8604+
scratch.clear();
8605+
8606+
switch (kind) {
8607+
case GeneratedSourceInfo::ExpressionMacroExpansion:
8608+
case GeneratedSourceInfo::FreestandingDeclMacroExpansion:
8609+
return expandedCode;
8610+
8611+
case GeneratedSourceInfo::AccessorMacroExpansion:
8612+
// For accessor macros, wrap curly braces around the buffer contents.
8613+
scratch += "{\n";
8614+
scratch += expandedCode;
8615+
scratch += "\n}";
8616+
return scratch;
8617+
8618+
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
8619+
// For member-attribute macros, add a space at the end.
8620+
scratch += expandedCode;
8621+
scratch += " ";
8622+
return scratch;
8623+
8624+
case GeneratedSourceInfo::PeerMacroExpansion:
8625+
// For peers, add a newline to create some separation.
8626+
scratch += "\n";
8627+
LLVM_FALLTHROUGH;
8628+
8629+
case GeneratedSourceInfo::MemberMacroExpansion:
8630+
// For members, add a newline.
8631+
scratch += "\n";
8632+
scratch += expandedCode;
8633+
scratch += "\n";
8634+
return scratch;
8635+
8636+
case GeneratedSourceInfo::ReplacedFunctionBody:
8637+
case GeneratedSourceInfo::PrettyPrinted:
8638+
return expandedCode;
8639+
}
8640+
}
8641+
85988642
bool RefactoringActionExpandMacro::performChange() {
85998643
auto bufferIDs = getMacroExpansionBuffers(SM, CursorInfo);
86008644
if (bufferIDs.empty())
@@ -8637,15 +8681,11 @@ bool RefactoringActionExpandMacro::performChange() {
86378681

86388682
auto afterLeftBraceLoc = Lexer::getLocForEndOfToken(SM, leftBraceLoc);
86398683
originalSourceRange = CharSourceRange(afterLeftBraceLoc, 0);
8640-
} else if (generatedInfo->kind ==
8641-
GeneratedSourceInfo::AccessorMacroExpansion) {
8642-
// For accessor macros, wrap curly braces around the buffer contents.
8643-
scratchBuffer += "{\n";
8644-
scratchBuffer += rewrittenBuffer;
8645-
scratchBuffer += "\n}";
8646-
rewrittenBuffer = scratchBuffer;
86478684
}
86488685

8686+
rewrittenBuffer = adjustMacroExpansionWhitespace(
8687+
generatedInfo->kind, rewrittenBuffer, scratchBuffer);
8688+
86498689
EditConsumer.accept(SM, originalSourceRange, rewrittenBuffer);
86508690

86518691
if (generatedInfo->attachedMacroCustomAttr && !attachedMacroAttr)

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1779,8 +1779,6 @@ bool swift::visitForwardedGuaranteedOperands(
17791779
|| isa<OwnershipForwardingMultipleValueInstruction>(inst)
17801780
|| isa<MoveOnlyWrapperToCopyableValueInst>(inst)
17811781
|| isa<CopyableToMoveOnlyWrapperValueInst>(inst)) {
1782-
assert(inst->getNumRealOperands() == 1
1783-
&& "forwarding instructions must have a single real operand");
17841782
assert(!isa<SingleValueInstruction>(inst)
17851783
|| !BorrowedValue(cast<SingleValueInstruction>(inst))
17861784
&& "forwarded operand cannot begin a borrow scope");

lib/Sema/CSApply.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7804,18 +7804,27 @@ Expr *ExprRewriter::finishApply(ApplyExpr *apply, Type openedType,
78047804
auto *body = args->getExpr(1);
78057805
auto bodyTy = cs.getType(body)->getWithoutSpecifierType();
78067806
auto bodyFnTy = bodyTy->castTo<FunctionType>();
7807-
auto escapableParams = bodyFnTy->getParams();
78087807
auto resultType = bodyFnTy->getResult();
78097808

78107809
// The body is immediately called, so is obviously noescape.
7810+
// Coerce the argument function to be escaping even if it happens to
7811+
// be nonescaping, since we need the dynamic state of the escaping
7812+
// closure to do the dynamic noescape check.
7813+
auto bodyArgFnTy = bodyFnTy->getParams()[0].getPlainType()
7814+
->castTo<FunctionType>();
7815+
7816+
bodyArgFnTy = cast<FunctionType>(
7817+
bodyArgFnTy->withExtInfo(bodyArgFnTy->getExtInfo().withNoEscape(false)));
78117818
bodyFnTy = cast<FunctionType>(
7812-
bodyFnTy->withExtInfo(bodyFnTy->getExtInfo().withNoEscape()));
7819+
FunctionType::get(bodyFnTy->getParams()[0].withType(bodyArgFnTy),
7820+
bodyFnTy->getResult())
7821+
->withExtInfo(bodyFnTy->getExtInfo().withNoEscape()));
78137822
body = coerceToType(body, bodyFnTy, locator);
78147823
assert(body && "can't make nonescaping?!");
78157824

78167825
auto escapable = new (ctx)
78177826
OpaqueValueExpr(apply->getFn()->getSourceRange(), Type());
7818-
cs.setType(escapable, escapableParams[0].getOldType());
7827+
cs.setType(escapable, bodyArgFnTy);
78197828

78207829
auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {escapable});
78217830
auto callSubExpr = CallExpr::createImplicit(ctx, body, argList);

lib/Sema/TypeCheckDeclPrimary.cpp

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2586,7 +2586,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
25862586

25872587
// FIXME(kavon): see if these can be integrated into other parts of Sema
25882588
diagnoseCopyableTypeContainingMoveOnlyType(ED);
2589-
diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(ED);
2589+
diagnoseIncompatibleProtocolsForMoveOnlyType(ED);
25902590

25912591
checkExplicitAvailability(ED);
25922592

@@ -2645,7 +2645,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
26452645
// are not move only.
26462646
diagnoseCopyableTypeContainingMoveOnlyType(SD);
26472647

2648-
diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(SD);
2648+
diagnoseIncompatibleProtocolsForMoveOnlyType(SD);
26492649
}
26502650

26512651
/// Check whether the given properties can be @NSManaged in this class.
@@ -2747,21 +2747,53 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
27472747
}
27482748
}
27492749

2750-
void diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(
2751-
NominalTypeDecl *nomDecl) {
2752-
if (!nomDecl->isMoveOnly())
2753-
return;
2750+
/// check to see if a move-only type can ever conform to the given type.
2751+
/// \returns true iff a diagnostic was emitted because it was not compatible
2752+
static bool diagnoseIncompatibleWithMoveOnlyType(SourceLoc loc,
2753+
NominalTypeDecl *moveonlyType,
2754+
Type type) {
2755+
assert(type && "got an empty type?");
2756+
assert(moveonlyType->isMoveOnly());
27542757

2755-
for (auto *prot : nomDecl->getLocalProtocols()) {
2758+
auto canType = type->getCanonicalType();
2759+
if (auto prot = canType->getAs<ProtocolType>()) {
27562760
// Permit conformance to marker protocol Sendable.
2757-
if (prot->isSpecificProtocol(KnownProtocolKind::Sendable)) {
2758-
assert(prot->isMarkerProtocol());
2759-
continue;
2761+
if (prot->getDecl()->isSpecificProtocol(KnownProtocolKind::Sendable)) {
2762+
assert(prot->getDecl()->isMarkerProtocol());
2763+
return false;
27602764
}
2765+
}
27612766

2762-
nomDecl->diagnose(diag::moveonly_cannot_conform_to_protocol_with_name,
2763-
nomDecl->getDescriptiveKind(),
2764-
nomDecl->getBaseName(), prot->getBaseName());
2767+
auto &ctx = moveonlyType->getASTContext();
2768+
ctx.Diags.diagnose(loc,
2769+
diag::moveonly_cannot_conform_to_type,
2770+
moveonlyType->getDescriptiveKind(),
2771+
moveonlyType->getBaseName(),
2772+
type);
2773+
return true;
2774+
}
2775+
2776+
static void diagnoseIncompatibleProtocolsForMoveOnlyType(Decl *decl) {
2777+
if (auto *nomDecl = dyn_cast<NominalTypeDecl>(decl)) {
2778+
if (!nomDecl->isMoveOnly())
2779+
return;
2780+
2781+
// go over the all protocols directly conformed-to by this nominal
2782+
for (auto *prot : nomDecl->getLocalProtocols())
2783+
diagnoseIncompatibleWithMoveOnlyType(nomDecl->getLoc(), nomDecl,
2784+
prot->getDeclaredInterfaceType());
2785+
2786+
} else if (auto *extension = dyn_cast<ExtensionDecl>(decl)) {
2787+
if (auto *nomDecl = extension->getExtendedNominal()) {
2788+
if (!nomDecl->isMoveOnly())
2789+
return;
2790+
2791+
// go over the all types directly conformed-to by the extension
2792+
for (auto entry : extension->getInherited()) {
2793+
diagnoseIncompatibleWithMoveOnlyType(extension->getLoc(), nomDecl,
2794+
entry.getType());
2795+
}
2796+
}
27652797
}
27662798
}
27672799

@@ -2928,7 +2960,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
29282960

29292961
maybeDiagnoseClassWithoutInitializers(CD);
29302962

2931-
diagnoseMoveOnlyNominalDeclDoesntConformToProtocols(CD);
2963+
diagnoseIncompatibleProtocolsForMoveOnlyType(CD);
29322964

29332965
// Ban non-final classes from having move only fields.
29342966
if (!CD->isFinal()) {
@@ -3404,11 +3436,7 @@ class DeclChecker : public DeclVisitor<DeclChecker> {
34043436
if (nominal->isDistributedActor())
34053437
TypeChecker::checkDistributedActor(SF, nominal);
34063438

3407-
// If we have a move only type and allow it to extend any protocol, error.
3408-
if (nominal->isMoveOnly() && ED->getInherited().size()) {
3409-
ED->diagnose(diag::moveonly_cannot_conform_to_protocol,
3410-
nominal->getDescriptiveKind(), nominal->getBaseName());
3411-
}
3439+
diagnoseIncompatibleProtocolsForMoveOnlyType(ED);
34123440

34133441
TypeChecker::checkReflectionMetadataAttributes(ED);
34143442
}

stdlib/public/core/Runtime.swift

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,16 +131,19 @@ func _stdlib_atomicInitializeARCRef(
131131
object target: UnsafeMutablePointer<AnyObject?>,
132132
desired: AnyObject
133133
) -> Bool {
134+
// Note: this assumes that AnyObject? is layout-compatible with a RawPointer
135+
// that simply points to the same memory.
134136
var expected: UnsafeRawPointer?
135-
let desiredPtr = Unmanaged.passRetained(desired).toOpaque()
137+
let unmanaged = Unmanaged.passRetained(desired)
138+
let desiredPtr = unmanaged.toOpaque()
136139
let rawTarget = UnsafeMutableRawPointer(target).assumingMemoryBound(
137140
to: Optional<UnsafeRawPointer>.self)
138141
let wonRace = _stdlib_atomicCompareExchangeStrongPtr(
139142
object: rawTarget, expected: &expected, desired: desiredPtr)
140143
if !wonRace {
141144
// Some other thread initialized the value. Balance the retain that we
142145
// performed on 'desired'.
143-
Unmanaged.passUnretained(desired).release()
146+
unmanaged.release()
144147
}
145148
return wonRace
146149
}
@@ -157,6 +160,44 @@ func _stdlib_atomicLoadARCRef(
157160
return nil
158161
}
159162

163+
@_transparent
164+
@_alwaysEmitIntoClient
165+
@discardableResult
166+
public func _stdlib_atomicAcquiringInitializeARCRef<T: AnyObject>(
167+
object target: UnsafeMutablePointer<T?>,
168+
desired: __owned T
169+
) -> Unmanaged<T> {
170+
// Note: this assumes that AnyObject? is layout-compatible with a RawPointer
171+
// that simply points to the same memory, and that `nil` is represented by an
172+
// all-zero bit pattern.
173+
let unmanaged = Unmanaged.passRetained(desired)
174+
let desiredPtr = unmanaged.toOpaque()
175+
176+
let (value, won) = Builtin.cmpxchg_acqrel_acquire_Word(
177+
target._rawValue,
178+
0._builtinWordValue,
179+
Builtin.ptrtoint_Word(desiredPtr._rawValue))
180+
181+
if Bool(won) { return unmanaged }
182+
183+
// Some other thread initialized the value before us. Balance the retain that
184+
// we performed on 'desired', and return what we loaded.
185+
unmanaged.release()
186+
let ptr = UnsafeRawPointer(Builtin.inttoptr_Word(value))
187+
return Unmanaged<T>.fromOpaque(ptr)
188+
}
189+
190+
@_alwaysEmitIntoClient
191+
@_transparent
192+
public func _stdlib_atomicAcquiringLoadARCRef<T: AnyObject>(
193+
object target: UnsafeMutablePointer<T?>
194+
) -> Unmanaged<T>? {
195+
let value = Builtin.atomicload_acquire_Word(target._rawValue)
196+
if Int(value) == 0 { return nil }
197+
let opaque = UnsafeRawPointer(Builtin.inttoptr_Word(value))
198+
return Unmanaged<T>.fromOpaque(opaque)
199+
}
200+
160201
//===----------------------------------------------------------------------===//
161202
// Conversion of primitive types to `String`
162203
//===----------------------------------------------------------------------===//

stdlib/public/core/StringStorage.swift

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -719,8 +719,18 @@ extension __SharedStringStorage {
719719

720720
// Get and populate breadcrumbs
721721
extension _StringGuts {
722+
/// Atomically load and return breadcrumbs, populating them if necessary.
723+
///
724+
/// This emits aquire/release barriers to avoid access reordering trouble.
725+
///
726+
/// This returns an unmanaged +0 reference to allow accessing breadcrumbs
727+
/// without incurring retain/release operations.
722728
@_effects(releasenone)
723-
internal func getBreadcrumbsPtr() -> UnsafePointer<_StringBreadcrumbs> {
729+
internal func loadUnmanagedBreadcrumbs() -> Unmanaged<_StringBreadcrumbs> {
730+
// FIXME: Returning Unmanaged emulates the original implementation (that
731+
// used to return a nonatomic pointer), but it may be an unnecessary
732+
// complication. (UTF-16 transcoding seems expensive enough not to worry
733+
// about retain overhead.)
724734
_internalInvariant(hasBreadcrumbs)
725735

726736
let mutPtr: UnsafeMutablePointer<_StringBreadcrumbs?>
@@ -731,25 +741,12 @@ extension _StringGuts {
731741
Builtin.addressof(&_object.sharedStorage._breadcrumbs))
732742
}
733743

734-
if _slowPath(mutPtr.pointee == nil) {
735-
populateBreadcrumbs(mutPtr)
744+
if let breadcrumbs = _stdlib_atomicAcquiringLoadARCRef(object: mutPtr) {
745+
return breadcrumbs
736746
}
737-
738-
_internalInvariant(mutPtr.pointee != nil)
739-
// assuming optional class reference and class reference can alias
740-
return UnsafeRawPointer(mutPtr).assumingMemoryBound(to: _StringBreadcrumbs.self)
741-
}
742-
743-
@inline(never) // slow-path
744-
@_effects(releasenone)
745-
internal func populateBreadcrumbs(
746-
_ mutPtr: UnsafeMutablePointer<_StringBreadcrumbs?>
747-
) {
748-
// Thread-safe compare-and-swap
749-
let crumbs = _StringBreadcrumbs(String(self))
750-
_stdlib_atomicInitializeARCRef(
751-
object: UnsafeMutableRawPointer(mutPtr).assumingMemoryBound(to: Optional<AnyObject>.self),
752-
desired: crumbs)
747+
let desired = _StringBreadcrumbs(String(self))
748+
return _stdlib_atomicAcquiringInitializeARCRef(
749+
object: mutPtr, desired: desired)
753750
}
754751
}
755752

stdlib/public/core/StringStorageBridge.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ extension _AbstractStringStorage {
4848
) {
4949
_precondition(aRange.location >= 0 && aRange.length >= 0,
5050
"Range out of bounds")
51+
// Note: `count` is counting UTF-8 code units, while `aRange` is measured in
52+
// UTF-16 offsets. This precondition is a necessary, but not sufficient test
53+
// for validity. (More precise checks are done in UTF16View._nativeCopy.)
5154
_precondition(aRange.location + aRange.length <= Int(count),
5255
"Range out of bounds")
5356

0 commit comments

Comments
 (0)