Merge pull request #10167 from slavapestov/default-arguments-versus-effective-access

Sema: Targeted fix for bad interaction between resilience checks and -enable-testing
diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h
index 9416e6d..f202dc2 100644
--- a/include/swift/AST/Decl.h
+++ b/include/swift/AST/Decl.h
@@ -2201,7 +2201,10 @@
   ///
   /// This is the access used when making optimization and code generation
   /// decisions. It should not be used at the AST or semantic level.
-  Accessibility getEffectiveAccess() const;
+  ///
+  /// If \p forLinkage is false, we ignore -enable-testing; only @_versioned
+  /// can increase visibility.
+  Accessibility getEffectiveAccess(bool forLinkage = true) const;
 
   void setAccessibility(Accessibility access) {
     assert(!hasAccessibility() && "accessibility already set");
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index bc11834..9974a64 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1359,7 +1359,7 @@
 
   // Private and (unversioned) internal variables always have a
   // fixed layout.
-  if (getEffectiveAccess() < Accessibility::Public)
+  if (getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
     return true;
 
   // Check for an explicit @_fixed_layout attribute.
@@ -1952,19 +1952,19 @@
   return Accessibility::Public;
 }
 
-Accessibility ValueDecl::getEffectiveAccess() const {
+Accessibility ValueDecl::getEffectiveAccess(bool forLinkage) const {
   Accessibility effectiveAccess = getFormalAccess();
 
   // Handle @testable.
   switch (effectiveAccess) {
   case Accessibility::Public:
-    if (getModuleContext()->isTestingEnabled())
+    if (forLinkage && getModuleContext()->isTestingEnabled())
       effectiveAccess = getTestableAccess(this);
     break;
   case Accessibility::Open:
     break;
   case Accessibility::Internal:
-    if (getModuleContext()->isTestingEnabled())
+    if (forLinkage && getModuleContext()->isTestingEnabled())
       effectiveAccess = getTestableAccess(this);
     else if (isVersionedInternalDecl(this))
       effectiveAccess = Accessibility::Public;
@@ -1978,7 +1978,7 @@
 
   if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(getDeclContext())) {
     effectiveAccess = std::min(effectiveAccess,
-                               enclosingNominal->getEffectiveAccess());
+                               enclosingNominal->getEffectiveAccess(forLinkage));
 
   } else if (auto enclosingExt = dyn_cast<ExtensionDecl>(getDeclContext())) {
     // Just check the base type. If it's a constrained extension, Sema should
@@ -1986,7 +1986,7 @@
     if (auto extendedTy = enclosingExt->getExtendedType()) {
       if (auto nominal = extendedTy->getAnyNominal()) {
         effectiveAccess = std::min(effectiveAccess,
-                                   nominal->getEffectiveAccess());
+                                   nominal->getEffectiveAccess(forLinkage));
       }
     }
 
@@ -2117,7 +2117,7 @@
 bool NominalTypeDecl::hasFixedLayout() const {
   // Private and (unversioned) internal types always have a
   // fixed layout.
-  if (getEffectiveAccess() < Accessibility::Public)
+  if (getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
     return true;
 
   // Check for an explicit @_fixed_layout attribute.
diff --git a/lib/AST/DeclContext.cpp b/lib/AST/DeclContext.cpp
index fb622e4..1cd1274 100644
--- a/lib/AST/DeclContext.cpp
+++ b/lib/AST/DeclContext.cpp
@@ -550,7 +550,7 @@
 
       // If the function is not externally visible, we will not be serializing
       // its body.
-      if (AFD->getEffectiveAccess() < Accessibility::Public)
+      if (AFD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public)
         break;
 
       // Bodies of public transparent and always-inline functions are
diff --git a/lib/Sema/ResilienceDiagnostics.cpp b/lib/Sema/ResilienceDiagnostics.cpp
index 9fd2894..a4fcb4f 100644
--- a/lib/Sema/ResilienceDiagnostics.cpp
+++ b/lib/Sema/ResilienceDiagnostics.cpp
@@ -91,7 +91,7 @@
     return false;
 
   // Public declarations are OK.
-  if (D->getEffectiveAccess() >= Accessibility::Public)
+  if (D->getEffectiveAccess(/*forLinkage=*/false) >= Accessibility::Public)
     return false;
 
   // Enum cases are handled as part of their containing enum.
@@ -110,7 +110,8 @@
 
   diagnose(loc, diag::resilience_decl_unavailable,
            D->getDescriptiveKind(), D->getFullName(),
-           D->getFormalAccess(), getFragileFunctionKind(DC));
+           D->getFormalAccessScope().accessibilityForDiagnostics(),
+           getFragileFunctionKind(DC));
   diagnose(D, diag::resilience_decl_declared_here,
            D->getDescriptiveKind(), D->getFullName());
   return true;
diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp
index b8290f5..46a952e 100644
--- a/lib/Sema/TypeCheckAttr.cpp
+++ b/lib/Sema/TypeCheckAttr.cpp
@@ -1824,19 +1824,14 @@
                                         /*allowConcreteGenericParams=*/true);
 }
 
-static Accessibility getAccessForDiagnostics(const ValueDecl *D) {
-  return std::min(D->getFormalAccess(),
-                  D->getEffectiveAccess());
-}
-
 void AttributeChecker::visitFixedLayoutAttr(FixedLayoutAttr *attr) {
   auto *VD = cast<ValueDecl>(D);
 
-  if (VD->getEffectiveAccess() < Accessibility::Public) {
+  if (VD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public) {
     TC.diagnose(attr->getLocation(),
                 diag::fixed_layout_attr_on_internal_type,
                 VD->getBaseName(),
-                getAccessForDiagnostics(VD))
+                VD->getFormalAccessScope().accessibilityForDiagnostics())
         .fixItRemove(attr->getRangeWithAt());
     attr->setInvalid();
   }
@@ -1886,13 +1881,11 @@
 
   // @_inlineable can only be applied to public or @_versioned
   // declarations.
-  if (VD->getFormalAccess() < Accessibility::Internal ||
-      (!VD->getAttrs().hasAttribute<VersionedAttr>() &&
-       VD->getFormalAccess() < Accessibility::Public)) {
+  if (VD->getEffectiveAccess(/*forLinkage=*/false) < Accessibility::Public) {
     TC.diagnose(attr->getLocation(),
                 diag::inlineable_decl_not_public,
                 VD->getBaseName(),
-                getAccessForDiagnostics(VD))
+                VD->getFormalAccessScope().accessibilityForDiagnostics())
         .fixItRemove(attr->getRangeWithAt());
     attr->setInvalid();
     return;
diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp
index 0cd11a2..dd1dcca 100644
--- a/lib/Sema/TypeCheckStmt.cpp
+++ b/lib/Sema/TypeCheckStmt.cpp
@@ -1321,7 +1321,7 @@
   // caller.
   auto expansion = func->getResilienceExpansion();
   if (!tc.Context.isSwiftVersion3() &&
-      func->getEffectiveAccess() == Accessibility::Public)
+      func->getEffectiveAccess(/*forLinkage=*/false) == Accessibility::Public)
     expansion = ResilienceExpansion::Minimal;
 
   for (auto &param : *params) {
diff --git a/test/attr/attr_fixed_layout.swift b/test/attr/attr_fixed_layout.swift
index be40c16..0eefb79 100644
--- a/test/attr/attr_fixed_layout.swift
+++ b/test/attr/attr_fixed_layout.swift
@@ -1,5 +1,7 @@
 // RUN: %target-swift-frontend -typecheck -verify -dump-ast -enable-resilience %s 2>&1 | %FileCheck --check-prefix=RESILIENCE-ON %s
+// RUN: %target-swift-frontend -typecheck -verify -dump-ast -enable-resilience -enable-testing %s 2>&1 | %FileCheck --check-prefix=RESILIENCE-ON %s
 // RUN: %target-swift-frontend -typecheck -verify -dump-ast %s 2>&1 | %FileCheck --check-prefix=RESILIENCE-OFF %s
+// RUN: %target-swift-frontend -typecheck -verify -dump-ast %s -enable-testing 2>&1 | %FileCheck --check-prefix=RESILIENCE-OFF %s
 
 //
 // Public types with @_fixed_layout are always fixed layout
diff --git a/test/attr/attr_inlineable.swift b/test/attr/attr_inlineable.swift
index 2c659fa..ebca886 100644
--- a/test/attr/attr_inlineable.swift
+++ b/test/attr/attr_inlineable.swift
@@ -1,4 +1,5 @@
 // RUN: %target-typecheck-verify-swift -swift-version 4
+// RUN: %target-typecheck-verify-swift -swift-version 4 -enable-testing
 
 @_inlineable struct TestInlineableStruct {}
 // expected-error@-1 {{@_inlineable cannot be applied to this declaration}}
diff --git a/test/attr/attr_versioned.swift b/test/attr/attr_versioned.swift
index 0d72404..9f6cb39 100644
--- a/test/attr/attr_versioned.swift
+++ b/test/attr/attr_versioned.swift
@@ -1,4 +1,5 @@
 // RUN: %target-typecheck-verify-swift
+// RUN: %target-typecheck-verify-swift -enable-testing
 
 @_versioned private func privateVersioned() {}
 // expected-error@-1 {{'@_versioned' attribute can only be applied to internal declarations, but 'privateVersioned' is private}}