Skip to content

Commit 4dcd8ca

Browse files
committed
add $SuppressedConformances feature flag
This will help prevent condfails when older compilers try to typecheck interfaces with `~Swift.Copyable` in them.
1 parent a9cb0ba commit 4dcd8ca

File tree

5 files changed

+89
-6
lines changed

5 files changed

+89
-6
lines changed

include/swift/AST/Decl.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,6 +1117,13 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
11171117
return getAttrs().hasAttribute<NoImplicitCopyAttr>();
11181118
}
11191119

1120+
/// Determines whether this Decl has any suppressed entries in its inheritance
1121+
/// clause, or within its generic context (e.g., its generic parameters).
1122+
///
1123+
/// IMPLEMENTATION NOTE: as of today this does _not_ look into 'where' clauses
1124+
/// but it probably should.
1125+
bool hasSuppressedConformance() const;
1126+
11201127
AvailabilityContext getAvailabilityForLinkage() const;
11211128

11221129
/// Whether this declaration or one of its outer contexts has the

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(
100100
hasSwiftSwiftParser)
101101
LANGUAGE_FEATURE(AttachedMacros, 389, "Attached macros", hasSwiftSwiftParser)
102102
LANGUAGE_FEATURE(MoveOnly, 390, "noncopyable types", true)
103+
LANGUAGE_FEATURE(SuppressedConformances, 390, "suppression of implicit conformance", true)
103104
LANGUAGE_FEATURE(ParameterPacks, 393, "Value and type parameter packs", true)
104105

105106
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)

lib/AST/ASTPrinter.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3276,6 +3276,34 @@ static bool usesFeatureMoveOnly(Decl *decl) {
32763276
return false;
32773277
}
32783278

3279+
static bool usesFeatureSuppressedConformances(Decl *decl) {
3280+
// first check the decl itself.
3281+
if (decl->hasSuppressedConformance())
3282+
return true;
3283+
3284+
// for extensions, check the type it extends.
3285+
if (auto *extnDecl = dyn_cast<ExtensionDecl>(decl))
3286+
if (auto *nom = extnDecl->getSelfNominalTypeDecl())
3287+
if (nom->hasSuppressedConformance())
3288+
return true;
3289+
3290+
// otherwise, search the decl's interface for a type with suppressed entries
3291+
if (auto value = dyn_cast<ValueDecl>(decl)) {
3292+
if (Type type = value->getInterfaceType()) {
3293+
return type.findIf([&](Type t) {
3294+
auto canType = t->getCanonicalType();
3295+
3296+
if (auto *decl = canType->getAnyNominal())
3297+
return decl->hasSuppressedConformance();
3298+
3299+
return false;
3300+
});
3301+
}
3302+
}
3303+
3304+
return false;
3305+
}
3306+
32793307
static bool usesFeatureMoveOnlyClasses(Decl *decl) {
32803308
return isa<ClassDecl>(decl) && usesFeatureMoveOnly(decl);
32813309
}

lib/AST/Decl.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10573,3 +10573,45 @@ MacroDiscriminatorContext::getParentOf(MacroExpansionDecl *expansion) {
1057310573
return getParentOf(
1057410574
expansion->getLoc(), expansion->getDeclContext());
1057510575
}
10576+
10577+
bool Decl::hasSuppressedConformance() const {
10578+
if (auto typeDecl = dyn_cast<TypeDecl>(this))
10579+
if (!typeDecl->getSuppressed().empty())
10580+
return true;
10581+
10582+
if (auto *gc = getAsGenericContext()) {
10583+
if (auto *genericParams = gc->getGenericParams()) {
10584+
auto suppressedParam =
10585+
llvm::any_of(genericParams->getParams(),
10586+
[](GenericTypeParamDecl const *param) {
10587+
return param->hasSuppressedConformance();
10588+
});
10589+
10590+
if (suppressedParam)
10591+
return true;
10592+
10593+
// TODO: eventually once where clauses support suppression, this ought to
10594+
// look for their corresponding requirements.
10595+
}
10596+
}
10597+
10598+
if (auto extnDecl = dyn_cast<ExtensionDecl>(this)) {
10599+
// NOTE: The presence of suppressed entries in extensions creates some
10600+
// difficulty in determining whether there is a suppressed conformance
10601+
// purely from looking at suppressed entries, as both the nominal and its
10602+
// extension has space for these entries. We'd need a form of lookup
10603+
// similar to conformance lookups that merges together all information
10604+
// from extensions and the original declaration to determine whether there
10605+
// was a suppressed entry anywhere. That's why the previous check for the
10606+
// TypeDecl is so simple, and doesn't search its extensions.
10607+
//
10608+
// Extensions with suppressed entries should have been rejected in
10609+
// type checking, so crash if there is one here.
10610+
if (!extnDecl->getSuppressed().empty())
10611+
llvm_unreachable("unexpected suppression in extension");
10612+
10613+
return false;
10614+
}
10615+
10616+
return false;
10617+
}

test/ModuleInterface/moveonly_interface_flag.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,30 @@
11
// RUN: %empty-directory(%t)
22
// RUN: %target-swift-emit-module-interface(%t/Library.swiftinterface) %s -module-name Library
33
// RUN: %target-swift-typecheck-module-from-interface(%t/Library.swiftinterface) -I %t
4-
// RUN: %FileCheck %s < %t/Library.swiftinterface
4+
// RUN: %FileCheck --implicit-check-not SuppressedConformances %s < %t/Library.swiftinterface
55

66
// this test makes sure that decls containing a move-only type are guarded by the $MoveOnly feature flag
77

8-
// CHECK: #if compiler(>=5.3) && $MoveOnly
8+
// CHECK: #if compiler(>=5.3) && $MoveOnly && $SuppressedConformances
99
// CHECK-NEXT: public struct MoveOnlyStruct : ~Swift.Copyable {
1010

1111
// CHECK: #if compiler(>=5.3) && $MoveOnly
1212
// CHECK-NEXT: @_moveOnly public struct OldAttr_MoveOnlyStruct {
1313

14-
// CHECK: #if compiler(>=5.3) && $MoveOnly
14+
// CHECK: #if compiler(>=5.3) && $MoveOnly && $SuppressedConformances
1515
// CHECK-NEXT: public enum MoveOnlyEnum : ~Swift.Copyable {
1616

17-
// CHECK: #if compiler(>=5.3) && $MoveOnly
17+
// CHECK: #if compiler(>=5.3) && $MoveOnly && $SuppressedConformances
1818
// CHECK-NEXT: public func someFn() -> Library.MoveOnlyEnum
1919

20+
// CHECK: #if compiler(>=5.3) && $MoveOnly
21+
// CHECK-NEXT: public func oldFn() -> Library.OldAttr_MoveOnlyStruct
22+
2023
// CHECK: public class What {
21-
// CHECK: #if compiler(>=5.3) && $MoveOnly
24+
// CHECK: #if compiler(>=5.3) && $MoveOnly && $SuppressedConformances
2225
// CHECK-NEXT: public func diamonds(_ f: (borrowing Library.MoveOnlyStruct) -> Swift.Int)
2326

24-
// CHECK: #if compiler(>=5.3) && $MoveOnly
27+
// CHECK: #if compiler(>=5.3) && $MoveOnly && $SuppressedConformances
2528
// CHECK-NEXT: extension Library.MoveOnlyStruct {
2629

2730
public struct MoveOnlyStruct : ~Copyable {
@@ -38,6 +41,8 @@ public enum MoveOnlyEnum : ~Copyable {
3841

3942
public func someFn() -> MoveOnlyEnum { return .depth }
4043

44+
public func oldFn() -> OldAttr_MoveOnlyStruct { return OldAttr_MoveOnlyStruct() }
45+
4146
public class What {
4247
public func diamonds(_ f: (borrowing MoveOnlyStruct) -> Int) {}
4348
}

0 commit comments

Comments
 (0)