Skip to content

[Re-merge] Support __available__((swift_attr("@Sendable"))) #40267

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 9 commits into from
Nov 29, 2021
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
2 changes: 1 addition & 1 deletion include/swift/AST/Attr.def
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(async, Async,
106)

SIMPLE_DECL_ATTR(Sendable, Sendable,
OnFunc | OnConstructor | OnAccessor |
OnFunc | OnConstructor | OnAccessor | OnAnyClangDecl |
ABIBreakingToAdd | ABIBreakingToRemove |
APIBreakingToAdd | APIBreakingToRemove,
107)
Expand Down
25 changes: 22 additions & 3 deletions include/swift/AST/Attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,9 @@ class DeclAttribute : public AttributeBase {
);

SWIFT_INLINE_BITFIELD(SynthesizedProtocolAttr, DeclAttribute,
NumKnownProtocolKindBits,
kind : NumKnownProtocolKindBits
NumKnownProtocolKindBits+1,
kind : NumKnownProtocolKindBits,
isUnchecked : 1
);
} Bits;

Expand Down Expand Up @@ -288,6 +289,9 @@ class DeclAttribute : public AttributeBase {

/// Whether this attribute is only valid when distributed is enabled.
DistributedOnly = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 17),

/// Whether this attribute is valid on additional decls in ClangImporter.
OnAnyClangDecl = 1ull << (unsigned(DeclKindIndex::Last_Decl) + 18),
};

LLVM_READNONE
Expand Down Expand Up @@ -1276,11 +1280,13 @@ class SynthesizedProtocolAttr : public DeclAttribute {

public:
SynthesizedProtocolAttr(KnownProtocolKind protocolKind,
LazyConformanceLoader *Loader)
LazyConformanceLoader *Loader,
bool isUnchecked)
: DeclAttribute(DAK_SynthesizedProtocol, SourceLoc(), SourceRange(),
/*Implicit=*/true), Loader(Loader)
{
Bits.SynthesizedProtocolAttr.kind = unsigned(protocolKind);
Bits.SynthesizedProtocolAttr.isUnchecked = unsigned(isUnchecked);
}

/// Retrieve the known protocol kind naming the protocol to be
Expand All @@ -1289,6 +1295,10 @@ class SynthesizedProtocolAttr : public DeclAttribute {
return KnownProtocolKind(Bits.SynthesizedProtocolAttr.kind);
}

bool isUnchecked() const {
return bool(Bits.SynthesizedProtocolAttr.isUnchecked);
}

/// Retrieve the lazy loader that will be used to populate the
/// synthesized conformance.
LazyConformanceLoader *getLazyLoader() const { return Loader; }
Expand Down Expand Up @@ -2217,6 +2227,15 @@ class DeclAttributes {
return nullptr;
}

/// Returns the "winning" \c NonSendableAttr or \c SendableAttr in this
/// attribute list, or \c nullptr if there are none.
const DeclAttribute *getEffectiveSendableAttr() const;

DeclAttribute *getEffectiveSendableAttr() {
return const_cast<DeclAttribute *>(
const_cast<const DeclAttributes *>(this)->getEffectiveSendableAttr());
}

private:
/// Predicate used to filter MatchingAttributeRange.
template <typename ATTR, bool AllowInvalid> struct ToAttributeKind {
Expand Down
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsClangImporter.def
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ NOTE(unresolvable_clang_decl_is_a_framework_bug,none,
WARNING(clang_swift_attr_unhandled,none,
"Ignoring unknown Swift attribute or modifier '%0'", (StringRef))

WARNING(clang_error_code_must_be_sendable,none,
"cannot make error code type '%0' non-sendable because Swift errors "
"are always sendable", (StringRef))

WARNING(implicit_bridging_header_imported_from_module,none,
"implicit import of bridging header '%0' via module %1 "
"is deprecated and will be removed in a later version of Swift",
Expand Down
18 changes: 14 additions & 4 deletions include/swift/AST/FileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
#include "swift/AST/RawComment.h"
#include "swift/Basic/BasicSourceInfo.h"

#include "llvm/ADT/PointerIntPair.h"

namespace swift {
class SynthesizedFileUnit;

/// A container for module-scope declarations that itself provides a scope; the
/// smallest unit of code organization.
///
Expand All @@ -33,19 +37,25 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
friend class DirectOperatorLookupRequest;
friend class DirectPrecedenceGroupLookupRequest;

// FIXME: Stick this in a PointerIntPair.
const FileUnitKind Kind;
// The pointer is FileUnit insted of SynthesizedFileUnit to break circularity.
llvm::PointerIntPair<FileUnit *, 3, FileUnitKind> SynthesizedFileAndKind;

protected:
FileUnit(FileUnitKind kind, ModuleDecl &M)
: DeclContext(DeclContextKind::FileUnit, &M), Kind(kind) {
: DeclContext(DeclContextKind::FileUnit, &M),
SynthesizedFileAndKind(nullptr, kind) {
}

public:
FileUnitKind getKind() const {
return Kind;
return SynthesizedFileAndKind.getInt();
}

/// Returns the synthesized file for this source file, if it exists.
SynthesizedFileUnit *getSynthesizedFile() const;

SynthesizedFileUnit &getOrCreateSynthesizedFile();

/// Look up a (possibly overloaded) value set at top-level scope
/// (but with the specified access path, which may come from an import decl)
/// within this file.
Expand Down
4 changes: 3 additions & 1 deletion include/swift/AST/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,9 @@ class ModuleDecl
/// The order of the results is not guaranteed to be meaningful.
///
/// This can differ from \c getTopLevelDecls, e.g. it returns decls from a
/// shadowed clang module.
/// shadowed clang module. It does not force synthesized top-level decls that
/// should be printed to be added; use \c swift::getTopLevelDeclsForDisplay()
/// for that.
void getDisplayDecls(SmallVectorImpl<Decl*> &results) const;

using LinkLibraryCallback = llvm::function_ref<void(LinkLibrary)>;
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/PrintOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ struct PrintOptions {
/// Whether to print unavailable parts of the AST.
bool SkipUnavailable = false;

/// Whether to print synthesized extensions created by '@_nonSendable', even
/// if SkipImplicit or SkipUnavailable is set.
bool AlwaysPrintNonSendableExtensions = true;

bool SkipSwiftPrivateClangDecls = false;

/// Whether to skip internal stdlib declarations.
Expand Down Expand Up @@ -667,6 +671,7 @@ struct PrintOptions {
PO.ShouldQualifyNestedDeclarations = QualifyNestedDeclarations::TypesOnly;
PO.PrintParameterSpecifiers = true;
PO.SkipImplicit = true;
PO.AlwaysPrintNonSendableExtensions = false;
PO.AlwaysTryPrintParameterLabels = true;
return PO;
}
Expand Down
7 changes: 7 additions & 0 deletions include/swift/AST/ProtocolConformance.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,13 @@ class NormalProtocolConformance : public RootProtocolConformance,
return ContextAndBits.getInt() & UncheckedFlag;
}

/// Mark the conformance as unchecked (equivalent to the @unchecked
/// conformance attribute).
void setUnchecked() {
// OK to mutate because the flags are not part of the folding set node ID.
ContextAndBits.setInt(ContextAndBits.getInt() | UncheckedFlag);
}

/// Get the kind of source from which this conformance comes.
ConformanceEntryKind getSourceKind() const {
return SourceKindAndImplyingConformance.getInt();
Expand Down
8 changes: 0 additions & 8 deletions include/swift/AST/SourceFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,6 @@ class SourceFile final : public FileUnit {
/// same module.
mutable Identifier PrivateDiscriminator;

/// A synthesized file corresponding to this file, created on-demand.
SynthesizedFileUnit *SynthesizedFile = nullptr;

/// The root TypeRefinementContext for this SourceFile.
///
/// This is set during type checking.
Expand Down Expand Up @@ -409,11 +406,6 @@ class SourceFile final : public FileUnit {
Optional<ExternalSourceLocs::RawLocs>
getExternalRawLocsForDecl(const Decl *D) const override;

/// Returns the synthesized file for this source file, if it exists.
SynthesizedFileUnit *getSynthesizedFile() const { return SynthesizedFile; };

SynthesizedFileUnit &getOrCreateSynthesizedFile();

virtual bool walk(ASTWalker &walker) override;

/// The buffer ID for the file that was imported, or None if there
Expand Down
8 changes: 3 additions & 5 deletions include/swift/AST/SynthesizedFileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@

namespace swift {

class SourceFile;

/// A container for synthesized declarations, attached to a `SourceFile`.
///
/// Currently, only module-level synthesized declarations are supported.
class SynthesizedFileUnit final : public FileUnit {
/// The parent source file.
SourceFile &SF;
FileUnit &FU;

/// Synthesized top level declarations.
TinyPtrVector<Decl *> TopLevelDecls;
Expand All @@ -36,11 +34,11 @@ class SynthesizedFileUnit final : public FileUnit {
mutable Identifier PrivateDiscriminator;

public:
SynthesizedFileUnit(SourceFile &SF);
SynthesizedFileUnit(FileUnit &FU);
~SynthesizedFileUnit() = default;

/// Returns the parent source file.
SourceFile &getSourceFile() const { return SF; }
FileUnit &getFileUnit() const { return FU; }

/// Add a synthesized top-level declaration.
void addTopLevelDecl(Decl *D) { TopLevelDecls.push_back(D); }
Expand Down
7 changes: 7 additions & 0 deletions include/swift/Sema/IDETypeChecking.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ namespace swift {
LookupResult
lookupSemanticMember(DeclContext *DC, Type ty, DeclName name);

/// Get all of the top-level declarations that should be printed as part of
/// this module. This may force synthesis of top-level declarations that
/// \c ModuleDecl::getDisplayDecls() would only return if previous
/// work happened to have synthesized them.
void
getTopLevelDeclsForDisplay(ModuleDecl *M, SmallVectorImpl<Decl*> &Results);

struct ExtensionInfo {
// The extension with the declarations to apply.
ExtensionDecl *Ext;
Expand Down
5 changes: 3 additions & 2 deletions lib/APIDigester/ModuleAnalyzerNodes.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#include "llvm/ADT/STLExtras.h"
#include "swift/AST/ASTMangler.h"
#include "swift/Basic/Defer.h"
#include "swift/Sema/IDETypeChecking.h"
#include "swift/SIL/SILDeclRef.h"
#include "swift/AST/ASTMangler.h"
#include <swift/APIDigester/ModuleAnalyzerNodes.h>
#include <algorithm>

Expand Down Expand Up @@ -1872,7 +1873,7 @@ void SwiftDeclCollector::printTopLevelNames() {
void SwiftDeclCollector::lookupVisibleDecls(ArrayRef<ModuleDecl *> Modules) {
for (auto M: Modules) {
llvm::SmallVector<Decl*, 512> Decls;
M->getDisplayDecls(Decls);
swift::getTopLevelDeclsForDisplay(M, Decls);
for (auto D : Decls) {
if (Ctx.shouldIgnore(D))
continue;
Expand Down
43 changes: 35 additions & 8 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1769,6 +1769,24 @@ bool ShouldPrintChecker::shouldPrint(const Pattern *P,
return ShouldPrint;
}

bool isNonSendableExtension(const Decl *D) {
ASTContext &ctx = D->getASTContext();

const ExtensionDecl *ED = dyn_cast<ExtensionDecl>(D);
if (!ED || !ED->getAttrs().isUnavailable(ctx))
return false;

auto nonSendable =
ED->getExtendedNominal()->getAttrs().getEffectiveSendableAttr();
if (!isa_and_nonnull<NonSendableAttr>(nonSendable))
return false;

// GetImplicitSendableRequest::evaluate() creates its extension with the
// attribute's AtLoc, so this is a good way to quickly check if the extension
// was synthesized for an '@_nonSendable' attribute.
return ED->getLocFromSource() == nonSendable->AtLoc;
}

bool ShouldPrintChecker::shouldPrint(const Decl *D,
const PrintOptions &Options) {
#if SWIFT_BUILD_ONLY_SYNTAXPARSERLIB
Expand All @@ -1791,15 +1809,18 @@ bool ShouldPrintChecker::shouldPrint(const Decl *D,
return false;
}

if (Options.SkipImplicit && D->isImplicit()) {
const auto &IgnoreList = Options.TreatAsExplicitDeclList;
if (std::find(IgnoreList.begin(), IgnoreList.end(), D) == IgnoreList.end())
// Optionally skip these checks for extensions synthesized for '@_nonSendable'
if (!Options.AlwaysPrintNonSendableExtensions || !isNonSendableExtension(D)) {
if (Options.SkipImplicit && D->isImplicit()) {
const auto &IgnoreList = Options.TreatAsExplicitDeclList;
if (!llvm::is_contained(IgnoreList, D))
return false;
}
}

if (Options.SkipUnavailable &&
D->getAttrs().isUnavailable(D->getASTContext()))
return false;
if (Options.SkipUnavailable &&
D->getAttrs().isUnavailable(D->getASTContext()))
return false;
}

if (Options.ExplodeEnumCaseDecls) {
if (isa<EnumElementDecl>(D))
Expand Down Expand Up @@ -5906,6 +5927,7 @@ swift::getInheritedForPrinting(
// Collect synthesized conformances.
auto &ctx = decl->getASTContext();
llvm::SetVector<ProtocolDecl *> protocols;
llvm::TinyPtrVector<ProtocolDecl *> uncheckedProtocols;
for (auto attr : decl->getAttrs().getAttributes<SynthesizedProtocolAttr>()) {
if (auto *proto = ctx.getProtocol(attr->getProtocolKind())) {
// The SerialExecutor conformance is only synthesized on the root
Expand All @@ -5918,11 +5940,14 @@ swift::getInheritedForPrinting(
cast<EnumDecl>(decl)->hasRawType())
continue;
protocols.insert(proto);
if (attr->isUnchecked())
uncheckedProtocols.push_back(proto);
}
}

for (size_t i = 0; i < protocols.size(); i++) {
auto proto = protocols[i];
bool isUnchecked = llvm::is_contained(uncheckedProtocols, proto);

if (!options.shouldPrint(proto)) {
// If private stdlib protocols are skipped and this is a private stdlib
Expand All @@ -5933,12 +5958,14 @@ swift::getInheritedForPrinting(
proto->isPrivateStdlibDecl(!options.SkipUnderscoredStdlibProtocols)) {
auto inheritedProtocols = proto->getInheritedProtocols();
protocols.insert(inheritedProtocols.begin(), inheritedProtocols.end());
if (isUnchecked)
copy(inheritedProtocols, std::back_inserter(uncheckedProtocols));
}
continue;
}

Results.push_back({TypeLoc::withoutLoc(proto->getDeclaredInterfaceType()),
/*isUnchecked=*/false});
isUnchecked});
}
}

Expand Down
26 changes: 26 additions & 0 deletions lib/AST/Attr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ DeclAttrKind DeclAttribute::getAttrKindFromString(StringRef Str) {

/// Returns true if this attribute can appear on the specified decl.
bool DeclAttribute::canAttributeAppearOnDecl(DeclAttrKind DK, const Decl *D) {
if ((getOptions(DK) & OnAnyClangDecl) && D->hasClangNode())
return true;
return canAttributeAppearOnDeclKind(DK, D->getKind());
}

Expand Down Expand Up @@ -699,6 +701,13 @@ void DeclAttributes::print(ASTPrinter &Printer, const PrintOptions &Options,
if (Options.excludeAttrKind(DA->getKind()))
continue;

// If this attribute is only allowed because this is a Clang decl, don't
// print it.
if (D && D->hasClangNode()
&& !DeclAttribute::canAttributeAppearOnDeclKind(
DA->getKind(), D->getKind()))
continue;

// Be careful not to coalesce `@available(swift 5)` with other short
// `available' attributes.
if (auto *availableAttr = dyn_cast<AvailableAttr>(DA)) {
Expand Down Expand Up @@ -2102,6 +2111,23 @@ TypeSequenceAttr *TypeSequenceAttr::create(ASTContext &Ctx, SourceLoc atLoc,
return new (mem) TypeSequenceAttr(atLoc, range);
}

const DeclAttribute *
DeclAttributes::getEffectiveSendableAttr() const {
const NonSendableAttr *assumedAttr = nullptr;

for (auto attr : getAttributes<NonSendableAttr>()) {
if (attr->Specificity == NonSendableKind::Specific)
return attr;
if (!assumedAttr)
assumedAttr = attr;
}

if (auto sendableAttr = getAttribute<SendableAttr>())
return sendableAttr;

return assumedAttr;
}

void swift::simple_display(llvm::raw_ostream &out, const DeclAttribute *attr) {
if (attr)
attr->print(out);
Expand Down
Loading