Skip to content

Commit 28beb03

Browse files
authored
Merge pull request swiftlang#10168 from slavapestov/default-arguments-versus-effective-access-v2
Sema: Targeted fix for bad interaction between resilience checks and -enable-testing [v2]
2 parents b0d9336 + 89dc5af commit 28beb03

File tree

7 files changed

+52
-36
lines changed

7 files changed

+52
-36
lines changed

include/swift/AST/Decl.h

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2162,6 +2162,8 @@ class ValueDecl : public Decl {
21622162
/// \see getFormalAccess
21632163
Accessibility getFormalAccessImpl(const DeclContext *useDC) const;
21642164

2165+
bool isVersionedInternalDecl() const;
2166+
21652167
/// Returns the access level specified explicitly by the user, or provided by
21662168
/// default according to language rules.
21672169
///
@@ -2171,9 +2173,16 @@ class ValueDecl : public Decl {
21712173
/// taken into account.
21722174
///
21732175
/// \sa getFormalAccessScope
2174-
Accessibility getFormalAccess(const DeclContext *useDC = nullptr) const {
2176+
Accessibility getFormalAccess(const DeclContext *useDC = nullptr,
2177+
bool respectVersionedAttr = false) const {
21752178
assert(hasAccessibility() && "accessibility not computed yet");
21762179
Accessibility result = TypeAndAccess.getInt().getValue();
2180+
if (respectVersionedAttr &&
2181+
result == Accessibility::Internal &&
2182+
isVersionedInternalDecl()) {
2183+
assert(!useDC);
2184+
return Accessibility::Public;
2185+
}
21772186
if (useDC && (result == Accessibility::Internal ||
21782187
result == Accessibility::Public))
21792188
return getFormalAccessImpl(useDC);
@@ -2194,17 +2203,15 @@ class ValueDecl : public Decl {
21942203
/// \sa getFormalAccess
21952204
/// \sa isAccessibleFrom
21962205
AccessScope
2197-
getFormalAccessScope(const DeclContext *useDC = nullptr) const;
2206+
getFormalAccessScope(const DeclContext *useDC = nullptr,
2207+
bool respectVersionedAttr = false) const;
21982208

21992209
/// Returns the access level that actually controls how a declaration should
22002210
/// be emitted and may be used.
22012211
///
22022212
/// This is the access used when making optimization and code generation
22032213
/// decisions. It should not be used at the AST or semantic level.
2204-
///
2205-
/// If \p forLinkage is false, we ignore -enable-testing; only @_versioned
2206-
/// can increase visibility.
2207-
Accessibility getEffectiveAccess(bool forLinkage = true) const;
2214+
Accessibility getEffectiveAccess() const;
22082215

22092216
void setAccessibility(Accessibility access) {
22102217
assert(!hasAccessibility() && "accessibility already set");

lib/AST/Decl.cpp

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,7 +1359,8 @@ bool AbstractStorageDecl::hasFixedLayout() const {
13591359

13601360
// Private and (unversioned) internal variables always have a
13611361
// fixed layout.
1362-
if (getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
1362+
if (!getFormalAccessScope(/*useDC=*/nullptr,
1363+
/*respectVersionedAttr=*/true).isPublic())
13631364
return true;
13641365

13651366
// Check for an explicit @_fixed_layout attribute.
@@ -1915,18 +1916,18 @@ SourceLoc ValueDecl::getAttributeInsertionLoc(bool forModifier) const {
19151916

19161917
/// Returns true if \p VD needs to be treated as publicly-accessible
19171918
/// at the SIL, LLVM, and machine levels due to being versioned.
1918-
static bool isVersionedInternalDecl(const ValueDecl *VD) {
1919-
assert(VD->getFormalAccess() == Accessibility::Internal);
1919+
bool ValueDecl::isVersionedInternalDecl() const {
1920+
assert(getFormalAccess() == Accessibility::Internal);
19201921

1921-
if (VD->getAttrs().hasAttribute<VersionedAttr>())
1922+
if (getAttrs().hasAttribute<VersionedAttr>())
19221923
return true;
19231924

1924-
if (auto *FD = dyn_cast<FuncDecl>(VD))
1925+
if (auto *FD = dyn_cast<FuncDecl>(this))
19251926
if (auto *ASD = FD->getAccessorStorageDecl())
19261927
if (ASD->getAttrs().hasAttribute<VersionedAttr>())
19271928
return true;
19281929

1929-
if (auto *EED = dyn_cast<EnumElementDecl>(VD))
1930+
if (auto *EED = dyn_cast<EnumElementDecl>(this))
19301931
if (EED->getParentEnum()->getAttrs().hasAttribute<VersionedAttr>())
19311932
return true;
19321933

@@ -1952,22 +1953,18 @@ static Accessibility getTestableAccess(const ValueDecl *decl) {
19521953
return Accessibility::Public;
19531954
}
19541955

1955-
Accessibility ValueDecl::getEffectiveAccess(bool forLinkage) const {
1956-
Accessibility effectiveAccess = getFormalAccess();
1956+
Accessibility ValueDecl::getEffectiveAccess() const {
1957+
auto effectiveAccess = getFormalAccess(/*useDC=*/nullptr,
1958+
/*respectVersionedAttr=*/true);
19571959

19581960
// Handle @testable.
19591961
switch (effectiveAccess) {
1960-
case Accessibility::Public:
1961-
if (forLinkage && getModuleContext()->isTestingEnabled())
1962-
effectiveAccess = getTestableAccess(this);
1963-
break;
19641962
case Accessibility::Open:
19651963
break;
1964+
case Accessibility::Public:
19661965
case Accessibility::Internal:
1967-
if (forLinkage && getModuleContext()->isTestingEnabled())
1966+
if (getModuleContext()->isTestingEnabled())
19681967
effectiveAccess = getTestableAccess(this);
1969-
else if (isVersionedInternalDecl(this))
1970-
effectiveAccess = Accessibility::Public;
19711968
break;
19721969
case Accessibility::FilePrivate:
19731970
break;
@@ -1978,15 +1975,15 @@ Accessibility ValueDecl::getEffectiveAccess(bool forLinkage) const {
19781975

19791976
if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(getDeclContext())) {
19801977
effectiveAccess = std::min(effectiveAccess,
1981-
enclosingNominal->getEffectiveAccess(forLinkage));
1978+
enclosingNominal->getEffectiveAccess());
19821979

19831980
} else if (auto enclosingExt = dyn_cast<ExtensionDecl>(getDeclContext())) {
19841981
// Just check the base type. If it's a constrained extension, Sema should
19851982
// have already enforced access more strictly.
19861983
if (auto extendedTy = enclosingExt->getExtendedType()) {
19871984
if (auto nominal = extendedTy->getAnyNominal()) {
19881985
effectiveAccess = std::min(effectiveAccess,
1989-
nominal->getEffectiveAccess(forLinkage));
1986+
nominal->getEffectiveAccess());
19901987
}
19911988
}
19921989

@@ -2008,23 +2005,28 @@ Accessibility ValueDecl::getFormalAccessImpl(const DeclContext *useDC) const {
20082005
return getFormalAccess();
20092006
}
20102007

2011-
AccessScope ValueDecl::getFormalAccessScope(const DeclContext *useDC) const {
2008+
AccessScope ValueDecl::getFormalAccessScope(const DeclContext *useDC,
2009+
bool respectVersionedAttr) const {
20122010
const DeclContext *result = getDeclContext();
2013-
Accessibility access = getFormalAccess(useDC);
2011+
Accessibility access = getFormalAccess(useDC, respectVersionedAttr);
20142012

20152013
while (!result->isModuleScopeContext()) {
20162014
if (result->isLocalContext() || access == Accessibility::Private)
20172015
return AccessScope(result, true);
20182016

20192017
if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(result)) {
2020-
access = std::min(access, enclosingNominal->getFormalAccess(useDC));
2018+
access = std::min(access,
2019+
enclosingNominal->getFormalAccess(useDC,
2020+
respectVersionedAttr));
20212021

20222022
} else if (auto enclosingExt = dyn_cast<ExtensionDecl>(result)) {
20232023
// Just check the base type. If it's a constrained extension, Sema should
20242024
// have already enforced access more strictly.
20252025
if (auto extendedTy = enclosingExt->getExtendedType()) {
20262026
if (auto nominal = extendedTy->getAnyNominal()) {
2027-
access = std::min(access, nominal->getFormalAccess(useDC));
2027+
access = std::min(access,
2028+
nominal->getFormalAccess(useDC,
2029+
respectVersionedAttr));
20282030
}
20292031
}
20302032

@@ -2117,7 +2119,8 @@ int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) {
21172119
bool NominalTypeDecl::hasFixedLayout() const {
21182120
// Private and (unversioned) internal types always have a
21192121
// fixed layout.
2120-
if (getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
2122+
if (!getFormalAccessScope(/*useDC=*/nullptr,
2123+
/*respectVersionedAttr=*/true).isPublic())
21212124
return true;
21222125

21232126
// Check for an explicit @_fixed_layout attribute.

lib/AST/DeclContext.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,8 @@ ResilienceExpansion DeclContext::getResilienceExpansion() const {
550550

551551
// If the function is not externally visible, we will not be serializing
552552
// its body.
553-
if (AFD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
553+
if (!AFD->getFormalAccessScope(/*useDC=*/nullptr,
554+
/*respectVersionedAttr=*/true).isPublic())
554555
break;
555556

556557
// Bodies of public transparent and always-inline functions are

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
9191
return false;
9292

9393
// Public declarations are OK.
94-
if (D->getEffectiveAccess(/*forLinkage=*/false) >= Accessibility::Public)
94+
if (D->getFormalAccessScope(/*useDC=*/nullptr,
95+
/*respectVersionedAttr=*/true).isPublic())
9596
return false;
9697

9798
// Enum cases are handled as part of their containing enum.

lib/Sema/TypeCheckAttr.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1827,11 +1827,13 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
18271827
void AttributeChecker::visitFixedLayoutAttr(FixedLayoutAttr *attr) {
18281828
auto *VD = cast<ValueDecl>(D);
18291829

1830-
if (VD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public) {
1830+
auto access = VD->getFormalAccess(/*useDC=*/nullptr,
1831+
/*respectVersionedAttr=*/true);
1832+
if (access < Accessibility::Public) {
18311833
TC.diagnose(attr->getLocation(),
18321834
diag::fixed_layout_attr_on_internal_type,
18331835
VD->getBaseName(),
1834-
VD->getFormalAccessScope().accessibilityForDiagnostics())
1836+
access)
18351837
.fixItRemove(attr->getRangeWithAt());
18361838
attr->setInvalid();
18371839
}
@@ -1881,11 +1883,13 @@ void AttributeChecker::visitInlineableAttr(InlineableAttr *attr) {
18811883

18821884
// @_inlineable can only be applied to public or @_versioned
18831885
// declarations.
1884-
if (VD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public) {
1886+
auto access = VD->getFormalAccess(/*useDC=*/nullptr,
1887+
/*respectVersionedAttr=*/true);
1888+
if (access < Accessibility::Public) {
18851889
TC.diagnose(attr->getLocation(),
18861890
diag::inlineable_decl_not_public,
18871891
VD->getBaseName(),
1888-
VD->getFormalAccessScope().accessibilityForDiagnostics())
1892+
access)
18891893
.fixItRemove(attr->getRangeWithAt());
18901894
attr->setInvalid();
18911895
return;

lib/Sema/TypeCheckStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,8 @@ static void checkDefaultArguments(TypeChecker &tc,
13211321
// caller.
13221322
auto expansion = func->getResilienceExpansion();
13231323
if (!tc.Context.isSwiftVersion3() &&
1324-
func->getEffectiveAccess(/*forLinkage=*/false) == Accessibility::Public)
1324+
func->getFormalAccessScope(/*useDC=*/nullptr,
1325+
/*respectVersionedAttr=*/true).isPublic())
13251326
expansion = ResilienceExpansion::Minimal;
13261327

13271328
for (auto &param : *params) {

test/attr/attr_fixed_layout.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ struct Rectangle {
5656
// expected-error@-1 {{'@_fixed_layout' attribute can only be applied to '@_versioned' or public declarations, but 'InternalStruct' is internal}}
5757

5858
@_fixed_layout public struct NestedStruct {}
59-
// expected-error@-1 {{'@_fixed_layout' attribute can only be applied to '@_versioned' or public declarations, but 'NestedStruct' is internal}}
6059
}
6160

6261
@_fixed_layout fileprivate struct FileprivateStruct {}

0 commit comments

Comments
 (0)