mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #85179 from xymus/exportability-nle-structs
Sema: Opt-in check for structs references to hidden dependencies in non-library-evolution mode
This commit is contained in:
@@ -6727,7 +6727,10 @@ public:
|
||||
///
|
||||
/// From the standpoint of access control and exportability checking, this
|
||||
/// var will behave as if it was public, even if it is internal or private.
|
||||
bool isLayoutExposedToClients() const;
|
||||
///
|
||||
/// If \p applyImplicit, consider implicitly exposed layouts as well.
|
||||
/// This applies to non-resilient modules.
|
||||
bool isLayoutExposedToClients(bool applyImplicit = false) const;
|
||||
|
||||
/// Is this a special debugger variable?
|
||||
bool isDebuggerVar() const { return Bits.VarDecl.IsDebuggerVar; }
|
||||
|
||||
@@ -474,7 +474,7 @@ SIMPLE_DECL_ATTR(_alwaysEmitIntoClient, AlwaysEmitIntoClient,
|
||||
83)
|
||||
|
||||
SIMPLE_DECL_ATTR(_implementationOnly, ImplementationOnly,
|
||||
OnImport | OnFunc | OnConstructor | OnVar | OnSubscript,
|
||||
OnImport | OnFunc | OnConstructor | OnVar | OnSubscript | OnStruct,
|
||||
UserInaccessible | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove | UnreachableInABIAttr,
|
||||
84)
|
||||
|
||||
|
||||
@@ -3847,7 +3847,8 @@ ERROR(decl_from_hidden_module,none,
|
||||
"%2 was not imported by this file|"
|
||||
"C++ types from imported module %2 do not support library evolution|"
|
||||
"it was imported via the internal bridging header|"
|
||||
"%2 was not imported publicly}3",
|
||||
"%2 was not imported publicly|"
|
||||
"it is a struct marked '@_implementationOnly'}3",
|
||||
(const Decl *, unsigned, Identifier, unsigned))
|
||||
ERROR(typealias_desugars_to_type_from_hidden_module,none,
|
||||
"%0 aliases '%1.%2' and cannot be used %select{here|"
|
||||
@@ -3865,7 +3866,8 @@ ERROR(typealias_desugars_to_type_from_hidden_module,none,
|
||||
"%4 was not imported by this file|"
|
||||
"C++ types from imported module %4 do not support library evolution|"
|
||||
"it was imported via the internal bridging header|"
|
||||
"%4 was not imported publicly}5",
|
||||
"%4 was not imported publicly|"
|
||||
"it is a struct marked '@_implementationOnly'}5",
|
||||
(const TypeAliasDecl *, StringRef, StringRef, unsigned, Identifier, unsigned))
|
||||
ERROR(conformance_from_implementation_only_module,none,
|
||||
"cannot use conformance of %0 to %1 %select{here|as property wrapper here|"
|
||||
@@ -3881,7 +3883,8 @@ ERROR(conformance_from_implementation_only_module,none,
|
||||
"%3 was not imported by this file|"
|
||||
"C++ types from imported module %3 do not support library evolution|"
|
||||
"it was imported via the internal bridging header|"
|
||||
"%3 was not imported publicly}4",
|
||||
"%3 was not imported publicly|"
|
||||
"it is a struct marked '@_implementationOnly'}4",
|
||||
(Type, Identifier, unsigned, Identifier, unsigned))
|
||||
NOTE(assoc_conformance_from_implementation_only_module,none,
|
||||
"in associated type %0 (inferred as %1)", (Type, Type))
|
||||
@@ -3946,6 +3949,9 @@ ERROR(implementation_only_override_import_without_attr,none,
|
||||
"override of %kindonly0 imported as implementation-only must be declared "
|
||||
"'@_implementationOnly'",
|
||||
(const ValueDecl *))
|
||||
ERROR(implementation_only_on_structs_feature,none,
|
||||
"'@_implementationOnly' on structs requires "
|
||||
"'-enable-experimental-feature CheckImplementationOnly'", ())
|
||||
|
||||
ERROR(import_attr_conflict,none,
|
||||
"%0 inconsistently imported with %1",
|
||||
@@ -4128,7 +4134,7 @@ WARNING(attr_has_no_effect_on_decl_with_access_level,none,
|
||||
(DeclAttribute, AccessLevel))
|
||||
ERROR(attr_not_on_decl_with_invalid_access_level,none,
|
||||
"'%0' may not be used on "
|
||||
"%select{private|fileprivate|internal|package|%error|%error}1 declarations",
|
||||
"%select{private|fileprivate|internal|package|public|%error}1 declarations",
|
||||
(DeclAttribute, AccessLevel))
|
||||
|
||||
ERROR(attr_has_no_effect_decl_not_available_before,none,
|
||||
@@ -7350,7 +7356,8 @@ ERROR(inlinable_decl_ref_from_hidden_module,
|
||||
"%2 was not imported by this file|"
|
||||
"C++ APIs from imported module %2 do not support library evolution|"
|
||||
"it was imported via the internal bridging header|"
|
||||
"%2 was not imported publicly}3",
|
||||
"%2 was not imported publicly|"
|
||||
"it is a struct marked '@_implementationOnly'}3",
|
||||
(const ValueDecl *, unsigned, Identifier, unsigned))
|
||||
|
||||
ERROR(inlinable_typealias_desugars_to_type_from_hidden_module,
|
||||
@@ -7362,7 +7369,8 @@ ERROR(inlinable_typealias_desugars_to_type_from_hidden_module,
|
||||
"%4 was not imported by this file|"
|
||||
"C++ types from imported module %4 do not support library evolution|"
|
||||
"it was imported via the internal bridging header|"
|
||||
"%4 was not imported publicly}5",
|
||||
"%4 was not imported publicly|"
|
||||
"it is a struct marked '@_implementationOnly'}5",
|
||||
(const TypeAliasDecl *, StringRef, StringRef, unsigned, Identifier, unsigned))
|
||||
|
||||
NOTE(missing_import_inserted,
|
||||
|
||||
@@ -558,6 +558,9 @@ EXPERIMENTAL_FEATURE(EmbeddedExistentials, false)
|
||||
/// Allow use of the 'anyAppleOS' availability domain.
|
||||
EXPERIMENTAL_FEATURE(AnyAppleOSAvailability, true)
|
||||
|
||||
/// Check @_implementationOnly imports in non-library-evolution mode.
|
||||
EXPERIMENTAL_FEATURE(CheckImplementationOnly, true)
|
||||
|
||||
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
|
||||
#undef EXPERIMENTAL_FEATURE
|
||||
#undef UPCOMING_FEATURE
|
||||
|
||||
@@ -1006,7 +1006,7 @@ bool swift::isExported(const ValueDecl *VD) {
|
||||
|
||||
// Is this a stored property in a @frozen struct or class?
|
||||
if (auto *property = dyn_cast<VarDecl>(VD))
|
||||
if (property->isLayoutExposedToClients())
|
||||
if (property->isLayoutExposedToClients(/*applyImplicit=*/true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -2753,20 +2753,33 @@ bool VarDecl::isInitExposedToClients() const {
|
||||
return hasInitialValue() && isLayoutExposedToClients();
|
||||
}
|
||||
|
||||
bool VarDecl::isLayoutExposedToClients() const {
|
||||
bool VarDecl::isLayoutExposedToClients(bool applyImplicit) const {
|
||||
auto parent = dyn_cast<NominalTypeDecl>(getDeclContext());
|
||||
if (!parent) return false;
|
||||
if (isStatic()) return false;
|
||||
|
||||
|
||||
auto M = getDeclContext()->getParentModule();
|
||||
auto nominalAccess =
|
||||
parent->getFormalAccessScope(/*useDC=*/nullptr,
|
||||
/*treatUsableFromInlineAsPublic=*/true);
|
||||
if (!nominalAccess.isPublic()) return false;
|
||||
|
||||
if (!parent->getAttrs().hasAttribute<FrozenAttr>() &&
|
||||
!parent->getAttrs().hasAttribute<FixedLayoutAttr>())
|
||||
// Resilient modules and classes hide layouts by default.
|
||||
bool layoutIsHiddenByDefault = !applyImplicit ||
|
||||
!getASTContext().LangOpts.hasFeature(Feature::CheckImplementationOnly) ||
|
||||
M->getResilienceStrategy() == ResilienceStrategy::Resilient;
|
||||
if (layoutIsHiddenByDefault) {
|
||||
if (!nominalAccess.isPublic())
|
||||
return false;
|
||||
|
||||
if (!parent->getAttrs().hasAttribute<FrozenAttr>() &&
|
||||
!parent->getAttrs().hasAttribute<FixedLayoutAttr>())
|
||||
return false;
|
||||
} else {
|
||||
// Non-resilient module: layouts are exposed by default unless marked
|
||||
// otherwise.
|
||||
if (parent->getAttrs().hasAttribute<ImplementationOnlyAttr>())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasStorage() &&
|
||||
!getAttrs().hasAttribute<LazyAttr>() &&
|
||||
|
||||
@@ -144,6 +144,7 @@ UNINTERESTING_FEATURE(ExtractConstantsFromMembers)
|
||||
UNINTERESTING_FEATURE(GroupActorErrors)
|
||||
UNINTERESTING_FEATURE(SameElementRequirements)
|
||||
UNINTERESTING_FEATURE(SendingArgsAndResults)
|
||||
UNINTERESTING_FEATURE(CheckImplementationOnly)
|
||||
|
||||
static bool findUnderscoredLifetimeAttr(Decl *decl) {
|
||||
auto hasUnderscoredLifetimeAttr = [](Decl *decl) {
|
||||
|
||||
@@ -338,6 +338,7 @@ static bool diagnoseValueDeclRefExportability(SourceLoc loc, const ValueDecl *D,
|
||||
|
||||
case DisallowedOriginKind::ImplementationOnly:
|
||||
case DisallowedOriginKind::FragileCxxAPI:
|
||||
case DisallowedOriginKind::ImplementationOnlyMemoryLayout:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -2163,6 +2163,14 @@ swift::getDisallowedOriginKind(const Decl *decl,
|
||||
Feature::AssumeResilientCxxTypes))
|
||||
return DisallowedOriginKind::FragileCxxAPI;
|
||||
|
||||
if (isa<StructDecl>(decl) || isa<EnumDecl>(decl)) {
|
||||
if (decl->getASTContext().LangOpts.hasFeature(
|
||||
Feature::CheckImplementationOnly) &&
|
||||
decl->getAttrs().hasAttribute<ImplementationOnlyAttr>()) {
|
||||
return DisallowedOriginKind::ImplementationOnlyMemoryLayout;
|
||||
}
|
||||
}
|
||||
|
||||
// Report non-public import last as it can be ignored by the caller.
|
||||
// See \c diagnoseValueDeclRefExportability.
|
||||
auto importSource = decl->getImportAccessFrom(where.getDeclContext());
|
||||
|
||||
@@ -32,7 +32,7 @@ class SourceFile;
|
||||
/// itself. Related checks may also be performed.
|
||||
void checkAccessControl(Decl *D);
|
||||
|
||||
/// Problematic origin of an exported type.
|
||||
/// Problematic origin of a decl that may restrict its exportability.
|
||||
///
|
||||
/// This enum must be kept in sync with a number of diagnostics:
|
||||
/// diag::inlinable_decl_ref_from_hidden_module
|
||||
@@ -52,6 +52,7 @@ enum class DisallowedOriginKind : uint8_t {
|
||||
InternalBridgingHeaderImport,
|
||||
|
||||
NonPublicImport,
|
||||
ImplementationOnlyMemoryLayout,
|
||||
None
|
||||
};
|
||||
|
||||
|
||||
@@ -4995,7 +4995,25 @@ AttributeChecker::visitImplementationOnlyAttr(ImplementationOnlyAttr *attr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// @_implementationOnly on structs only applies to non-public types.
|
||||
auto *VD = cast<ValueDecl>(D);
|
||||
if (isa<StructDecl>(VD)) {
|
||||
if (!Ctx.LangOpts.hasFeature(Feature::CheckImplementationOnly)) {
|
||||
diagnoseAndRemoveAttr(attr,
|
||||
diag::implementation_only_on_structs_feature);
|
||||
return;
|
||||
}
|
||||
|
||||
auto access =
|
||||
VD->getFormalAccessScope(/*useDC=*/nullptr,
|
||||
/*treatUsableFromInlineAsPublic=*/true);
|
||||
if (access.isPublicOrPackage())
|
||||
diagnoseAndRemoveAttr(
|
||||
attr, diag::attr_not_on_decl_with_invalid_access_level,
|
||||
attr, access.accessLevelForDiagnostics());
|
||||
return;
|
||||
}
|
||||
|
||||
auto *overridden = VD->getOverriddenDecl();
|
||||
if (!overridden) {
|
||||
diagnoseAndRemoveAttr(attr, diag::implementation_only_decl_non_override);
|
||||
|
||||
224
test/Sema/hidden-memory-layout.swift
Normal file
224
test/Sema/hidden-memory-layout.swift
Normal file
@@ -0,0 +1,224 @@
|
||||
/// Test @_implementationOnly import exportability diagnostics in non-library-evolution mode
|
||||
|
||||
/// Standard / non-embedded
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule \
|
||||
// RUN: %S/Inputs/implementation-only-imports/indirects.swift \
|
||||
// RUN: -swift-version 5
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t\
|
||||
// RUN: %S/Inputs/implementation-only-imports/directs.swift \
|
||||
// RUN: -swift-version 5
|
||||
|
||||
/// Old diags
|
||||
// RUN: %target-swift-frontend -emit-module -verify -verify-ignore-unrelated %s -I %t \
|
||||
// RUN: -swift-version 5 \
|
||||
// RUN: -verify-additional-prefix not-opt-in-
|
||||
|
||||
/// New diags
|
||||
// RUN: %target-swift-frontend -emit-module -verify -verify-ignore-unrelated %s -I %t \
|
||||
// RUN: -swift-version 5 \
|
||||
// RUN: -verify-additional-prefix opt-in- -DUseImplementationOnly \
|
||||
// RUN: -enable-experimental-feature CheckImplementationOnly
|
||||
|
||||
/// Embedded
|
||||
/// Will also show errors in non-@_neverEmitIntoClient functions.
|
||||
|
||||
// RUN: %empty-directory(%t)
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/indirects.swiftmodule \
|
||||
// RUN: %S/Inputs/implementation-only-imports/indirects.swift \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded
|
||||
// RUN: %target-swift-frontend -emit-module -o %t/directs.swiftmodule -I %t\
|
||||
// RUN: %S/Inputs/implementation-only-imports/directs.swift \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded
|
||||
|
||||
/// Old diags
|
||||
// RUN: %target-swift-frontend -emit-module -verify -verify-ignore-unrelated %s -I %t \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded \
|
||||
// RUN: -verify-additional-prefix not-opt-in-
|
||||
|
||||
/// New diags
|
||||
// RUN: %target-swift-frontend -emit-module -verify -verify-ignore-unrelated %s -I %t \
|
||||
// RUN: -swift-version 5 -target arm64-apple-none-macho \
|
||||
// RUN: -enable-experimental-feature Embedded \
|
||||
// RUN: -verify-additional-prefix opt-in- -DUseImplementationOnly \
|
||||
// RUN: -verify-additional-prefix embedded-opt-in- \
|
||||
// RUN: -enable-experimental-feature CheckImplementationOnly
|
||||
|
||||
// REQUIRES: swift_feature_Embedded
|
||||
// REQUIRES: swift_feature_CheckImplementationOnly
|
||||
// REQUIRES: embedded_stdlib_cross_compiling
|
||||
|
||||
@_implementationOnly import directs
|
||||
// expected-warning @-1 {{using '@_implementationOnly' without enabling library evolution for 'main' may lead to instability during execution}}
|
||||
import indirects
|
||||
|
||||
/// Referenced types
|
||||
|
||||
public struct ExposedLayoutPublic {
|
||||
public init() { fatalError() }
|
||||
}
|
||||
|
||||
internal struct ExposedLayoutInternal {
|
||||
}
|
||||
|
||||
private struct ExposedLayoutPrivate {
|
||||
// expected-note @-1 2 {{struct 'ExposedLayoutPrivate' is not '@usableFromInline' or public}}
|
||||
init() { fatalError() } // expected-note {{initializer 'init()' is not '@usableFromInline' or public}}
|
||||
}
|
||||
|
||||
#if UseImplementationOnly
|
||||
@_implementationOnly
|
||||
private struct HiddenLayout {
|
||||
// expected-opt-in-note @-1 2 {{struct 'HiddenLayout' is not '@usableFromInline' or public}}
|
||||
// expected-opt-in-note @-2 1 {{initializer 'init()' is not '@usableFromInline' or public}}
|
||||
// expected-opt-in-note @-3 2 {{struct declared here}}
|
||||
// expected-opt-in-note @-4 {{struct declared here}}
|
||||
}
|
||||
#else
|
||||
private struct HiddenLayout {
|
||||
// expected-not-opt-in-note @-1 2 {{struct 'HiddenLayout' is not '@usableFromInline' or public}}
|
||||
// expected-not-opt-in-note @-2 1 {{initializer 'init()' is not '@usableFromInline' or public}}
|
||||
}
|
||||
#endif
|
||||
|
||||
public enum ExposedEnumPublic {
|
||||
case A
|
||||
case B
|
||||
}
|
||||
|
||||
private enum ExposedEnumPrivate {
|
||||
// expected-note @-1 2 {{enum 'ExposedEnumPrivate' is not '@usableFromInline' or public}}
|
||||
case A
|
||||
// expected-note @-1 1 {{enum case 'A' is not '@usableFromInline' or public}}
|
||||
case B
|
||||
}
|
||||
|
||||
/// Function use sites
|
||||
|
||||
@inlinable
|
||||
public func explicitlyInlinable() {
|
||||
let _: ExposedLayoutPublic = ExposedLayoutPublic()
|
||||
let _: ExposedLayoutPrivate = ExposedLayoutPrivate()
|
||||
// expected-error @-1 2 {{struct 'ExposedLayoutPrivate' is private and cannot be referenced from an '@inlinable' function}}
|
||||
// expected-error @-2 {{initializer 'init()' is private and cannot be referenced from an '@inlinable' function}}
|
||||
|
||||
let _: HiddenLayout = HiddenLayout()
|
||||
// expected-error @-1 2 {{struct 'HiddenLayout' is private and cannot be referenced from an '@inlinable' function}}
|
||||
// expected-error @-2 {{initializer 'init()' is private and cannot be referenced from an '@inlinable' function}}
|
||||
|
||||
let _: ExposedEnumPublic = ExposedEnumPublic.A
|
||||
let _: ExposedEnumPrivate = ExposedEnumPrivate.A
|
||||
// expected-error @-1 2 {{enum 'ExposedEnumPrivate' is private and cannot be referenced from an '@inlinable' function}}
|
||||
// expected-error @-2 {{enum case 'A' is private and cannot be referenced from an '@inlinable' function}}
|
||||
}
|
||||
|
||||
public func implicitlyInlinablePublic() {
|
||||
let _: ExposedLayoutPublic = ExposedLayoutPublic()
|
||||
let _: ExposedLayoutPrivate = ExposedLayoutPrivate()
|
||||
let _: HiddenLayout = HiddenLayout()
|
||||
// expected-embedded-opt-in-error @-1 2 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because it is a struct marked '@_implementationOnly'}}
|
||||
|
||||
let _: ExposedEnumPublic = ExposedEnumPublic.A
|
||||
let _: ExposedEnumPrivate = ExposedEnumPrivate.A
|
||||
}
|
||||
|
||||
private func implicitlyInlinablePrivate() {
|
||||
let _: ExposedLayoutPublic = ExposedLayoutPublic()
|
||||
let _: ExposedLayoutPrivate = ExposedLayoutPrivate()
|
||||
let _: HiddenLayout = HiddenLayout()
|
||||
// expected-embedded-opt-in-error @-1 2 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because it is a struct marked '@_implementationOnly'}}
|
||||
|
||||
let _: ExposedEnumPublic = ExposedEnumPublic.A
|
||||
let _: ExposedEnumPrivate = ExposedEnumPrivate.A
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
public func explicitNonInliable() {
|
||||
let _: ExposedLayoutPublic = ExposedLayoutPublic()
|
||||
let _: ExposedLayoutPrivate = ExposedLayoutPrivate()
|
||||
let _: HiddenLayout = HiddenLayout()
|
||||
let _: ExposedEnumPublic = ExposedEnumPublic.A
|
||||
let _: ExposedEnumPrivate = ExposedEnumPrivate.A
|
||||
}
|
||||
|
||||
@_neverEmitIntoClient
|
||||
internal func explicitNonInliableInternal() {
|
||||
let _: ExposedLayoutPublic = ExposedLayoutPublic()
|
||||
let _: ExposedLayoutPrivate = ExposedLayoutPrivate()
|
||||
let _: HiddenLayout = HiddenLayout()
|
||||
let _: ExposedEnumPublic = ExposedEnumPublic.A
|
||||
let _: ExposedEnumPrivate = ExposedEnumPrivate.A
|
||||
}
|
||||
|
||||
/// Struct use sites
|
||||
|
||||
public struct ExposedLayoutPublicUser {
|
||||
|
||||
public var publicField: StructFromDirect
|
||||
// expected-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
|
||||
|
||||
private var privateField: StructFromDirect
|
||||
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
|
||||
|
||||
private var a: ExposedLayoutPublic
|
||||
private var aa: ExposedLayoutInternal
|
||||
private var b: ExposedLayoutPrivate
|
||||
|
||||
private var c: HiddenLayout
|
||||
// expected-opt-in-error @-1 {{cannot use struct 'HiddenLayout' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; it is a struct marked '@_implementationOnly'}}
|
||||
|
||||
private func privateFunc(h: HiddenLayout) {}
|
||||
// expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because it is a struct marked '@_implementationOnly'}}
|
||||
}
|
||||
|
||||
private struct ExposedLayoutInternalUser {
|
||||
|
||||
private var privateField: StructFromDirect
|
||||
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
|
||||
|
||||
private var a: ExposedLayoutPublic
|
||||
private var aa: ExposedLayoutInternal
|
||||
private var b: ExposedLayoutPrivate
|
||||
private var c: HiddenLayout
|
||||
// expected-opt-in-error @-1 {{cannot use struct 'HiddenLayout' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; it is a struct marked '@_implementationOnly'}}
|
||||
|
||||
private func privateFunc(h: HiddenLayout) {}
|
||||
// expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because it is a struct marked '@_implementationOnly'}}
|
||||
}
|
||||
|
||||
private struct ExposedLayoutPrivateUser {
|
||||
|
||||
private var privateField: StructFromDirect
|
||||
// expected-opt-in-error @-1 {{cannot use struct 'StructFromDirect' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; 'directs' has been imported as implementation-only}}
|
||||
|
||||
private var a: ExposedLayoutPublic
|
||||
private var aa: ExposedLayoutInternal
|
||||
private var b: ExposedLayoutPrivate
|
||||
private var c: HiddenLayout
|
||||
// expected-opt-in-error @-1 {{cannot use struct 'HiddenLayout' in a property declaration marked public or in a '@frozen' or '@usableFromInline' context; it is a struct marked '@_implementationOnly'}}
|
||||
|
||||
private func privateFunc(h: HiddenLayout) {}
|
||||
// expected-embedded-opt-in-error @-1 {{struct 'HiddenLayout' cannot be used in an embedded function not marked '@_neverEmitIntoClient' because it is a struct marked '@_implementationOnly'}}
|
||||
}
|
||||
|
||||
#if UseImplementationOnly
|
||||
@_implementationOnly
|
||||
private struct HiddenLayoutUser {
|
||||
public var publicField: StructFromDirect
|
||||
private var privateField: StructFromDirect
|
||||
private var a: ExposedLayoutPublic
|
||||
private var aa: ExposedLayoutInternal
|
||||
private var b: ExposedLayoutPrivate
|
||||
private var c: HiddenLayout
|
||||
|
||||
@_neverEmitIntoClient
|
||||
private func privateFunc(h: HiddenLayout) {}
|
||||
}
|
||||
|
||||
@_implementationOnly // expected-opt-in-error {{'@_implementationOnly' may not be used on public declarations}}
|
||||
public struct PublicHiddenStruct {}
|
||||
#endif
|
||||
Reference in New Issue
Block a user