Merge pull request #79655 from DougGregor/se-0458-condfails

[SE-0458] Improve backward compatibility of generated Swift interfaces
This commit is contained in:
Doug Gregor
2025-02-27 02:55:24 -08:00
committed by GitHub
4 changed files with 52 additions and 7 deletions

View File

@@ -2901,14 +2901,12 @@ void PrintAST::printInherited(const Decl *decl) {
Printer << "@preconcurrency ";
switch (inherited.getExplicitSafety()) {
case ExplicitSafety::Unspecified:
break;
case ExplicitSafety::Safe:
Printer << "@safe ";
break;
case ExplicitSafety::Unsafe:
Printer << "@unsafe ";
if (!llvm::is_contained(Options.ExcludeAttrList, TypeAttrKind::Unsafe))
Printer << "@unsafe ";
break;
}
if (inherited.isSuppressed())
@@ -3218,6 +3216,12 @@ suppressingFeatureMemorySafetyAttributes(PrintOptions &options,
llvm::function_ref<void()> action) {
ExcludeAttrRAII scope(options.ExcludeAttrList, DeclAttrKind::Unsafe);
ExcludeAttrRAII scope2(options.ExcludeAttrList, DeclAttrKind::Safe);
options.ExcludeAttrList.push_back(TypeAttrKind::Unsafe);
SWIFT_DEFER {
assert(options.ExcludeAttrList.back() == TypeAttrKind::Unsafe);
options.ExcludeAttrList.pop_back();
};
action();
}

View File

@@ -18,6 +18,7 @@
#include "swift/AST/NameLookup.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/Pattern.h"
#include "swift/AST/ProtocolConformance.h"
#include "clang/AST/DeclObjC.h"
#include "swift/Basic/Assertions.h"
@@ -350,8 +351,32 @@ static bool usesFeatureIsolatedConformances(Decl *decl) {
}
static bool usesFeatureMemorySafetyAttributes(Decl *decl) {
return decl->getAttrs().hasAttribute<SafeAttr>() ||
decl->getAttrs().hasAttribute<UnsafeAttr>();
if (decl->getAttrs().hasAttribute<SafeAttr>() ||
decl->getAttrs().hasAttribute<UnsafeAttr>())
return true;
IterableDeclContext *idc;
if (auto nominal = dyn_cast<NominalTypeDecl>(decl))
idc = nominal;
else if (auto ext = dyn_cast<ExtensionDecl>(decl))
idc = ext;
else
idc = nullptr;
// Look for an @unsafe conformance ascribed to this declaration.
if (idc) {
auto conformances = idc->getLocalConformances();
for (auto conformance : conformances) {
auto rootConformance = conformance->getRootConformance();
if (auto rootNormalConformance =
dyn_cast<NormalProtocolConformance>(rootConformance)) {
if (rootNormalConformance->getExplicitSafety() == ExplicitSafety::Unsafe)
return true;
}
}
}
return false;
}
UNINTERESTING_FEATURE(StrictMemorySafety)

View File

@@ -552,6 +552,10 @@ fileprivate class RemoveUnsafeExprSyntaxRewriter: SyntaxRewriter {
override func visit(_ node: UnsafeExprSyntax) -> ExprSyntax {
return node.expression.with(\.leadingTrivia, node.leadingTrivia)
}
override func visit(_ node: ForStmtSyntax) -> StmtSyntax {
return StmtSyntax(node.with(\.unsafeKeyword, nil))
}
}
extension SyntaxProtocol {

View File

@@ -9,10 +9,21 @@
// CHECK: #endif
@unsafe public func getIntUnsafely() -> Int { 0 }
public struct UnsafeIterator: @unsafe IteratorProtocol {
@unsafe public mutating func next() -> Int? { nil }
}
public struct SequenceWithUnsafeIterator: Sequence {
public init() { }
public func makeIterator() -> UnsafeIterator { UnsafeIterator() }
}
// CHECK: @inlinable public func useUnsafeCode()
@inlinable public func useUnsafeCode() {
// CHECK-NOT: unsafe
print( unsafe getIntUnsafely())
for unsafe _ in SequenceWithUnsafeIterator() { }
}
// CHECK: public protocol P
@@ -20,11 +31,12 @@ public protocol P {
func f()
}
// CHECK: #if compiler(>=5.3) && $MemorySafetyAttributes
// CHECK: public struct X : @unsafe UserModule.P
public struct X: @unsafe P {
// CHECK: #if compiler(>=5.3) && $MemorySafetyAttributes
// CHECK: @unsafe public func f()
// CHECK: #else
// CHECK: public struct X : UserModule.P
// CHECK: public func f()
// CHECK: #endif
@unsafe public func f() { }