Skip to content

[move-only] A group of batched changes #65353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions include/swift/AST/DiagnosticsSIL.def
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ ERROR(exclusivity_access_required_unknown_decl,none,
"%select{initialization|read|modification|deinitialization}0 requires "
"exclusive access; consider copying to a local variable", (unsigned))

ERROR(exclusivity_access_required_moveonly,none,
"overlapping accesses to %0, but "
"%select{initialization|read|modification|deinitialization}1 requires "
"exclusive access",
(StringRef, unsigned))

ERROR(exclusivity_access_required_unknown_decl_moveonly,none,
"overlapping accesses, but "
"%select{initialization|read|modification|deinitialization}0 requires "
"exclusive access", (unsigned))

NOTE(exclusivity_conflicting_access,none,
"conflicting access is here", ())

Expand Down
17 changes: 15 additions & 2 deletions include/swift/AST/SemanticAttrs.def
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,21 @@ SEMANTICS_ATTR(LIFETIMEMANAGEMENT_COPY, "lifetimemanagement.copy")

SEMANTICS_ATTR(NO_PERFORMANCE_ANALYSIS, "no_performance_analysis")

// A flag used to turn off moveonly diagnostics on functions that allocbox to
// stack specialized.
// A flag used to turn off moveonly diagnostics on a function due to an earlier
// pass that ran.
//
// DISCUSSION: This is used in a few situations:
//
// 1. When allocbox to stack specializes a function, we do not want to emit move
// errors twice, once on the specialized and once on the original
// function. Instead, we put this on the original function.
//
// 2. If we emit a diagnose invalid escaping captures error due to an inout
// being escaped into an escaping closure, we do not want to emit move errors in
// the closure. This is because SILGen today assumes that we will error in such
// cases and thus does not emit markers in said function for the inout. This
// then causes us to emit spurious "found a copy of a noncopyable value" errors
// that may cause the user to think there is a bug in the compiler.
SEMANTICS_ATTR(NO_MOVEONLY_DIAGNOSTICS, "sil.optimizer.moveonly.diagnostic.ignore")

#undef SEMANTICS_ATTR
Expand Down
24 changes: 24 additions & 0 deletions include/swift/Basic/NoDiscard.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===--- NoDiscard.h ------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_BASIC_NODISCARD_H
#define SWIFT_BASIC_NODISCARD_H

#if __cplusplus > 201402l && __has_cpp_attribute(nodiscard)
#define SWIFT_NODISCARD [[nodiscard]]
#elif __has_cpp_attribute(clang::warn_unused_result)
#define SWIFT_NODISCARD [[clang::warn_unused_result]]
#else
#define SWIFT_NODISCARD
#endif

#endif
26 changes: 26 additions & 0 deletions include/swift/SIL/AddressUseKind.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===--- AddressUseKind.h -------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SIL_ADDRESSUSEKIND_H
#define SWIFT_SIL_ADDRESSUSEKIND_H

namespace swift {

enum class AddressUseKind { NonEscaping, PointerEscape, Unknown };

inline AddressUseKind meet(AddressUseKind lhs, AddressUseKind rhs) {
return (lhs > rhs) ? lhs : rhs;
}

} // namespace swift

#endif
84 changes: 84 additions & 0 deletions include/swift/SIL/AddressWalker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//===--- AddressWalker.h --------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
///
/// \file
///
/// This header defines a walker for SIL addresses that is guaranteed by the
/// language to be able to traverse the SIL from an address def to all of its
/// transitive uses. This is validated by the SIL optimizer.
///
//===----------------------------------------------------------------------===//

#ifndef SWIFT_SIL_ADDRESSWALKER_H
#define SWIFT_SIL_ADDRESSWALKER_H

#include "swift/SIL/AddressUseKind.h"
#include "swift/SIL/SILValue.h"

namespace swift {

/// A state structure for findTransitiveUsesForAddress. Intended to be only used
/// a single time. Please always use a new one for every call to
/// findTransitiveUsesForAddress.
///
/// Validated by the SIL verifier as always being able to visit all addresses
/// derived from alloc_stack, ref_element_addr, project_box, ref_tail_addr and
/// all other address roots.
class TransitiveAddressWalker {
/// Whether we could tell if this address use didn't escape, did have a
/// pointer escape, or unknown if we failed to understand something.
AddressUseKind result = AddressUseKind::NonEscaping;

unsigned didInvalidate = false;

public:
virtual ~TransitiveAddressWalker() {}

protected:
/// Customization point for visiting uses. Returns true if we should continue
/// visiting.
///
/// NOTE: Do not call this directly from within
/// findTransitiveUsesForAddress. Please call callVisitUse. This is intended
/// just for subclasses to override.
virtual bool visitUse(Operand *use) { return true; }

virtual void onError(Operand *use) {}

void meet(AddressUseKind other) {
assert(!didInvalidate);
result = swift::meet(result, other);
}

private:
/// Shim that actually calls visitUse and changes early exit.
void callVisitUse(Operand *use) {
assert(!didInvalidate);
if (!visitUse(use))
result = AddressUseKind::Unknown;
}

public:
AddressUseKind walk(SILValue address) &&;
};

/// The algorithm that is used to determine what the verifier will consider to
/// be transitive uses of the given address. Used to implement \see
/// findTransitiveUses.
///
/// Returns \p AccessUseKind::Unknown on error.
AddressUseKind findTransitiveUsesForAddress(SILValue address,
TransitiveAddressWalker &visitor);

} // namespace swift

#endif
68 changes: 58 additions & 10 deletions include/swift/SIL/OwnershipUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#include "swift/Basic/Debug.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/NoDiscard.h"
#include "swift/SIL/AddressWalker.h"
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/SILArgument.h"
#include "swift/SIL/SILBasicBlock.h"
Expand Down Expand Up @@ -753,19 +755,65 @@ bool getAllBorrowIntroducingValues(SILValue value,
/// introducer, then we return a .some(BorrowScopeIntroducingValue).
BorrowedValue getSingleBorrowIntroducingValue(SILValue inputValue);

enum class AddressUseKind { NonEscaping, PointerEscape, Unknown };

inline AddressUseKind meet(AddressUseKind lhs, AddressUseKind rhs) {
return (lhs > rhs) ? lhs : rhs;
}

/// The algorithm that is used to determine what the verifier will consider to
/// be transitive uses of the given address. Used to implement \see
/// findTransitiveUses.
AddressUseKind
findTransitiveUsesForAddress(SILValue address,
SmallVectorImpl<Operand *> *foundUses = nullptr,
std::function<void(Operand *)> *onError = nullptr);
///
/// NOTE: Rather than return load_borrow as uses, this returns all of the
/// transitive uses of the load_borrow as uses. This is important when working
/// with this in OSSA. If one wishes to avoid this behavior, call find
/// transitive uses for address with ones own visitor.
inline AddressUseKind findTransitiveUsesForAddress(
SILValue address, SmallVectorImpl<Operand *> *foundUses = nullptr,
std::function<void(Operand *)> *onError = nullptr) {
// This is a version of TransitiveUseVisitor that visits inner transitive
// guaranteed uses to determine if a load_borrow is an escape in OSSA. This
// is OSSA specific behavior and we should probably create a different API
// for that. But for now, this lets this APIs users stay the same.
struct BasicTransitiveAddressVisitor final : TransitiveAddressWalker {
SmallVectorImpl<Operand *> *foundUses;
std::function<void(Operand *)> *onErrorFunc;

BasicTransitiveAddressVisitor(SmallVectorImpl<Operand *> *foundUses,
std::function<void(Operand *)> *onErrorFunc)
: foundUses(foundUses), onErrorFunc(onErrorFunc) {}

bool visitUse(Operand *use) override {
if (!foundUses)
return true;

if (auto *lbi = dyn_cast<LoadBorrowInst>(use->getUser())) {
if (!findInnerTransitiveGuaranteedUses(lbi, foundUses)) {
meet(AddressUseKind::PointerEscape);
}
return true;
}

// If we have a begin_apply, we want to use the token results if we have
// any. If it doesn't have any token results, we just make our use the
// begin_apply use itself below.
if (auto *bai = dyn_cast<BeginApplyInst>(use->getUser())) {
if (!bai->getTokenResult()->use_empty()) {
for (auto *use : bai->getTokenResult()->getUses()) {
foundUses->push_back(use);
}
return true;
}
}

foundUses->push_back(use);
return true;
}

void onError(Operand *use) override {
if (onErrorFunc)
(*onErrorFunc)(use);
}
};

BasicTransitiveAddressVisitor visitor(foundUses, onError);
return std::move(visitor).walk(address);
}

class InteriorPointerOperandKind {
public:
Expand Down
6 changes: 6 additions & 0 deletions include/swift/SILOptimizer/Analysis/AccessSummaryAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,12 @@ class AccessSummaryAnalysis : public BottomUpIPAnalysis {
SILModule &M,
TypeExpansionContext context);

/// Returns the type associated with the subpath \p SubPath.
///
/// \p BaseType must be the type of the root of the path.
static SILType getSubPathType(SILType BaseType, const IndexTrieNode *SubPath,
SILModule &M, TypeExpansionContext context);

/// Performs a lexicographic comparison of two subpaths, first by path length
/// and then by index of the last path component. Returns true when lhs
/// is less than rhs.
Expand Down
Loading