Skip to content

Commit 66173a9

Browse files
committed
Sema: Targeted fix for bad interaction between resilience checks and -enable-testing
The -enable-testing flag makes ValueDecl::getEffectiveAccess() say that internal declarations are public. This would lead us to emit spurious diagnostics if a default argument of an internal function referenced a private symbol, for example, which is something we actually want to allow. Hack around this by adding a new 'forLinkage' parameter to getEffectiveAccess(). When this is false, we ignore the -enable-testing flag, and only look for the @_versioned attribute. I'm not very happy with the fix, because it only compliates the subtle behaviors of getFormalAccess(), getEffectiveAccess() and getFormalAccessScope() further. But refactoring this is a bigger change than I'm willing to put into swift-4.0-branch. Fixes <rdar://problem/32592973>.
1 parent e87bba9 commit 66173a9

File tree

9 files changed

+24
-23
lines changed

9 files changed

+24
-23
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2201,7 +2201,10 @@ class ValueDecl : public Decl {
22012201
///
22022202
/// This is the access used when making optimization and code generation
22032203
/// decisions. It should not be used at the AST or semantic level.
2204-
Accessibility getEffectiveAccess() const;
2204+
///
2205+
/// If \p forLinkage is false, we ignore -enable-testing; only @_versioned
2206+
/// can increase visibility.
2207+
Accessibility getEffectiveAccess(bool forLinkage = true) const;
22052208

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

lib/AST/Decl.cpp

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

13601360
// Private and (unversioned) internal variables always have a
13611361
// fixed layout.
1362-
if (getEffectiveAccess() < Accessibility::Public)
1362+
if (getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
13631363
return true;
13641364

13651365
// Check for an explicit @_fixed_layout attribute.
@@ -1952,19 +1952,19 @@ static Accessibility getTestableAccess(const ValueDecl *decl) {
19521952
return Accessibility::Public;
19531953
}
19541954

1955-
Accessibility ValueDecl::getEffectiveAccess() const {
1955+
Accessibility ValueDecl::getEffectiveAccess(bool forLinkage) const {
19561956
Accessibility effectiveAccess = getFormalAccess();
19571957

19581958
// Handle @testable.
19591959
switch (effectiveAccess) {
19601960
case Accessibility::Public:
1961-
if (getModuleContext()->isTestingEnabled())
1961+
if (forLinkage && getModuleContext()->isTestingEnabled())
19621962
effectiveAccess = getTestableAccess(this);
19631963
break;
19641964
case Accessibility::Open:
19651965
break;
19661966
case Accessibility::Internal:
1967-
if (getModuleContext()->isTestingEnabled())
1967+
if (forLinkage && getModuleContext()->isTestingEnabled())
19681968
effectiveAccess = getTestableAccess(this);
19691969
else if (isVersionedInternalDecl(this))
19701970
effectiveAccess = Accessibility::Public;
@@ -1978,15 +1978,15 @@ Accessibility ValueDecl::getEffectiveAccess() const {
19781978

19791979
if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(getDeclContext())) {
19801980
effectiveAccess = std::min(effectiveAccess,
1981-
enclosingNominal->getEffectiveAccess());
1981+
enclosingNominal->getEffectiveAccess(forLinkage));
19821982

19831983
} else if (auto enclosingExt = dyn_cast<ExtensionDecl>(getDeclContext())) {
19841984
// Just check the base type. If it's a constrained extension, Sema should
19851985
// have already enforced access more strictly.
19861986
if (auto extendedTy = enclosingExt->getExtendedType()) {
19871987
if (auto nominal = extendedTy->getAnyNominal()) {
19881988
effectiveAccess = std::min(effectiveAccess,
1989-
nominal->getEffectiveAccess());
1989+
nominal->getEffectiveAccess(forLinkage));
19901990
}
19911991
}
19921992

@@ -2117,7 +2117,7 @@ int TypeDecl::compare(const TypeDecl *type1, const TypeDecl *type2) {
21172117
bool NominalTypeDecl::hasFixedLayout() const {
21182118
// Private and (unversioned) internal types always have a
21192119
// fixed layout.
2120-
if (getEffectiveAccess() < Accessibility::Public)
2120+
if (getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
21212121
return true;
21222122

21232123
// Check for an explicit @_fixed_layout attribute.

lib/AST/DeclContext.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,7 @@ 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() < Accessibility::Public)
553+
if (AFD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
554554
break;
555555

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

lib/Sema/ResilienceDiagnostics.cpp

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

9393
// Public declarations are OK.
94-
if (D->getEffectiveAccess() >= Accessibility::Public)
94+
if (D->getEffectiveAccess(/*forLinkage=*/false) >= Accessibility::Public)
9595
return false;
9696

9797
// Enum cases are handled as part of their containing enum.
@@ -110,7 +110,8 @@ bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
110110

111111
diagnose(loc, diag::resilience_decl_unavailable,
112112
D->getDescriptiveKind(), D->getFullName(),
113-
D->getFormalAccess(), getFragileFunctionKind(DC));
113+
D->getFormalAccessScope().accessibilityForDiagnostics(),
114+
getFragileFunctionKind(DC));
114115
diagnose(D, diag::resilience_decl_declared_here,
115116
D->getDescriptiveKind(), D->getFullName());
116117
return true;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1824,19 +1824,14 @@ void AttributeChecker::visitSpecializeAttr(SpecializeAttr *attr) {
18241824
/*allowConcreteGenericParams=*/true);
18251825
}
18261826

1827-
static Accessibility getAccessForDiagnostics(const ValueDecl *D) {
1828-
return std::min(D->getFormalAccess(),
1829-
D->getEffectiveAccess());
1830-
}
1831-
18321827
void AttributeChecker::visitFixedLayoutAttr(FixedLayoutAttr *attr) {
18331828
auto *VD = cast<ValueDecl>(D);
18341829

1835-
if (VD->getEffectiveAccess() < Accessibility::Public) {
1830+
if (VD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public) {
18361831
TC.diagnose(attr->getLocation(),
18371832
diag::fixed_layout_attr_on_internal_type,
18381833
VD->getBaseName(),
1839-
getAccessForDiagnostics(VD))
1834+
VD->getFormalAccessScope().accessibilityForDiagnostics())
18401835
.fixItRemove(attr->getRangeWithAt());
18411836
attr->setInvalid();
18421837
}
@@ -1886,13 +1881,11 @@ void AttributeChecker::visitInlineableAttr(InlineableAttr *attr) {
18861881

18871882
// @_inlineable can only be applied to public or @_versioned
18881883
// declarations.
1889-
if (VD->getFormalAccess() < Accessibility::Internal ||
1890-
(!VD->getAttrs().hasAttribute<VersionedAttr>() &&
1891-
VD->getFormalAccess() < Accessibility::Public)) {
1884+
if (VD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public) {
18921885
TC.diagnose(attr->getLocation(),
18931886
diag::inlineable_decl_not_public,
18941887
VD->getBaseName(),
1895-
getAccessForDiagnostics(VD))
1888+
VD->getFormalAccessScope().accessibilityForDiagnostics())
18961889
.fixItRemove(attr->getRangeWithAt());
18971890
attr->setInvalid();
18981891
return;

lib/Sema/TypeCheckStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1321,7 +1321,7 @@ static void checkDefaultArguments(TypeChecker &tc,
13211321
// caller.
13221322
auto expansion = func->getResilienceExpansion();
13231323
if (!tc.Context.isSwiftVersion3() &&
1324-
func->getEffectiveAccess() == Accessibility::Public)
1324+
func->getEffectiveAccess(/*forLinkage=*/false) == Accessibility::Public)
13251325
expansion = ResilienceExpansion::Minimal;
13261326

13271327
for (auto &param : *params) {

test/attr/attr_fixed_layout.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %target-swift-frontend -typecheck -verify -dump-ast -enable-resilience %s 2>&1 | %FileCheck --check-prefix=RESILIENCE-ON %s
2+
// RUN: %target-swift-frontend -typecheck -verify -dump-ast -enable-resilience -enable-testing %s 2>&1 | %FileCheck --check-prefix=RESILIENCE-ON %s
23
// RUN: %target-swift-frontend -typecheck -verify -dump-ast %s 2>&1 | %FileCheck --check-prefix=RESILIENCE-OFF %s
4+
// RUN: %target-swift-frontend -typecheck -verify -dump-ast %s -enable-testing 2>&1 | %FileCheck --check-prefix=RESILIENCE-OFF %s
35

46
//
57
// Public types with @_fixed_layout are always fixed layout

test/attr/attr_inlineable.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-typecheck-verify-swift -swift-version 4
2+
// RUN: %target-typecheck-verify-swift -swift-version 4 -enable-testing
23

34
@_inlineable struct TestInlineableStruct {}
45
// expected-error@-1 {{@_inlineable cannot be applied to this declaration}}

test/attr/attr_versioned.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-typecheck-verify-swift
2+
// RUN: %target-typecheck-verify-swift -enable-testing
23

34
@_versioned private func privateVersioned() {}
45
// expected-error@-1 {{'@_versioned' attribute can only be applied to internal declarations, but 'privateVersioned' is private}}

0 commit comments

Comments
 (0)