Teach getEffectiveAccess() to respect -enable-testing.

SIL seems to be doing the right thing here already, which is great!

Part of rdar://problem/17732115. We'll be able to really see this working
with the next change: allowing references to testable things when using
"@testable import".

Swift SVN r26473
This commit is contained in:
Jordan Rose
2015-03-24 02:17:01 +00:00
parent f74bc7122c
commit a0c64d7533
11 changed files with 97 additions and 32 deletions

View File

@@ -2057,16 +2057,12 @@ public:
return TypeAndAccess.getInt().getValue();
}
/// Returns the access level that actually controls how a declaration may be
/// used.
/// Returns the access level that actually controls how a declaration should
/// be emitted and may be used.
///
/// This is the access used when deciding whether a particular declaration
/// is only accessible from the current module. For declarations from other
/// modules, it behaves identically to getFormalAccess(). Rather than check
/// for this yourself, just use isAccessibleFrom() instead.
Accessibility getEffectiveAccess() const {
return getFormalAccess();
}
/// 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;
void setAccessibility(Accessibility access) {
assert(!hasAccessibility() && "accessibility already set");
@@ -5504,6 +5500,23 @@ inline bool ValueDecl::isSettable(DeclContext *UseDC) const {
return false;
}
namespace impl {
bool isTestingEnabled(const ValueDecl *VD);
}
inline Accessibility ValueDecl::getEffectiveAccess() const {
switch (getFormalAccess()) {
case Accessibility::Public:
return Accessibility::Public;
case Accessibility::Internal:
if (impl::isTestingEnabled(this))
return Accessibility::Public;
return Accessibility::Internal;
case Accessibility::Private:
return Accessibility::Private;
}
}
inline Optional<VarDecl *>
NominalTypeDecl::ToStoredProperty::operator()(Decl *decl) const {
if (auto var = dyn_cast<VarDecl>(decl)) {

View File

@@ -180,9 +180,6 @@ def enable_objc_implicit_properties :
def enable_source_import : Flag<["-"], "enable-source-import">,
HelpText<"Enable importing of Swift source files">;
def enable_testing : Flag<["-"], "enable-testing">,
HelpText<"Allows this module's internal API to be accessed for testing">;
def diagnose_generic_extensions : Flag<["-"], "diagnose-generic-extensions">,
HelpText<"Diagnose extensions of generic types without type parameters">;

View File

@@ -413,4 +413,8 @@ def embed_bitcode_marker : Flag<["-"], "embed-bitcode-marker">,
Flags<[FrontendOption, NoInteractiveOption]>,
HelpText<"Embed placeholder LLVM IR data as a marker">;
def enable_testing : Flag<["-"], "enable-testing">,
Flags<[FrontendOption, NoInteractiveOption, HelpHidden]>,
HelpText<"Allows this module's internal API to be accessed for testing">;
include "FrontendOptions.td"

View File

@@ -40,6 +40,10 @@
using namespace swift;
bool impl::isTestingEnabled(const ValueDecl *VD) {
return VD->getModuleContext()->isTestingEnabled();
}
clang::SourceLocation ClangNode::getLocation() const {
if (auto D = getAsDecl())
return D->getLocation();

View File

@@ -109,6 +109,7 @@ static void addCommonFrontendArgs(const ToolChain &TC,
inputArgs.AddLastArg(arguments, options::OPT_autolink_force_load);
inputArgs.AddLastArg(arguments, options::OPT_color_diagnostics);
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);
inputArgs.AddLastArg(arguments, options::OPT_enable_testing);
inputArgs.AddLastArg(arguments, options::OPT_g_Group);
inputArgs.AddLastArg(arguments, options::OPT_import_objc_header);
inputArgs.AddLastArg(arguments, options::OPT_import_underlying_module);

View File

@@ -5,6 +5,10 @@
// RUN: %target-swift-frontend -emit-sil -O -primary-file %s %S/Inputs/whole_module_optimization_helper.swift -o %t.unopt.sil -module-name main
// RUN: FileCheck %s -check-prefix=CHECK-SINGLE-FILE < %t.unopt.sil
// RUN: %target-swift-frontend -emit-sil -O -enable-testing %s %S/Inputs/whole_module_optimization_helper.swift -o %t.testing.sil -module-name main
// RUN: FileCheck %s < %t.testing.sil
// RUN: FileCheck %s -check-prefix=NEGATIVE-TESTABLE < %t.testing.sil
private func privateFn() -> Int32 {
return 2
}
@@ -28,4 +32,6 @@ public func getAnswer() -> Int32 {
// CHECK-SINGLE-FILE: }
// NEGATIVE-NOT: sil {{.+}}privateFn
// NEGATIVE-TESTABLE-NOT: sil {{.+}}privateFn
// NEGATIVE-NOT: sil {{.+}}compute
// CHECK-TESTABLE: sil {{.+}}compute

View File

@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -O -primary-file %s -emit-ir | FileCheck %s
// RUN: %target-swift-frontend -O -primary-file %s -emit-ir | FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s
// RUN: %target-swift-frontend -O -primary-file %s -enable-testing -emit-ir | FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s
// Check if the hashValue and == for an enum (without payload) are generated and
// check if that functions are compiled in an optimal way.
@@ -12,12 +13,14 @@ enum E {
// Check if the hashValue getter can be compiled to a simple zext instruction.
// CHECK-LABEL:define hidden i{{.*}} @_TFO12enum_derived1Eg9hashValueSi(i2)
// CHECK-NORMAL-LABEL:define hidden i{{.*}} @_TFO12enum_derived1Eg9hashValueSi(i2)
// CHECK-TESTABLE-LABEL:define i{{.*}} @_TFO12enum_derived1Eg9hashValueSi(i2)
// CHECK: %1 = zext i2 %0 to i{{.*}}
// CHECK: ret i{{.*}} %1
// Check if the == comparison can be compiled to a simple icmp instruction.
// CHECK-LABEL:define hidden i1 @_TZF12enum_derivedoi2eeFTOS_1ES0__Sb(i2, i2)
// CHECK-NORMAL-LABEL:define hidden i1 @_TZF12enum_derivedoi2eeFTOS_1ES0__Sb(i2, i2)
// CHECK-TESTABLE-LABEL:define i1 @_TZF12enum_derivedoi2eeFTOS_1ES0__Sb(i2, i2)
// CHECK: %2 = icmp eq i2 %0, %1
// CHECK: ret i1 %2

View File

@@ -1,7 +1,11 @@
// RUN: %target-swift-frontend -emit-silgen -parse-stdlib -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module > %t.sil
// RUN: FileCheck -check-prefix=TABLE %s < %t.sil
// RUN: FileCheck -check-prefix=TABLE -check-prefix=TABLE-ALL %s < %t.sil
// RUN: FileCheck -check-prefix=SYMBOL %s < %t.sil
// RUN: %target-swift-frontend -emit-silgen -parse-stdlib -I %S/Inputs -enable-source-import %s -disable-objc-attr-requires-foundation-module -enable-testing > %t.testable.sil
// RUN: FileCheck -check-prefix=TABLE-TESTABLE -check-prefix=TABLE-ALL %s < %t.testable.sil
// RUN: FileCheck -check-prefix=SYMBOL-TESTABLE %s < %t.testable.sil
import witness_tables_b
struct Arg {}
@@ -57,9 +61,11 @@ struct ConformingAssoc : AssocReqt {
func requiredMethod() {}
}
// TABLE-LABEL: sil_witness_table hidden ConformingAssoc: AssocReqt module witness_tables {
// TABLE-NEXT: method #AssocReqt.requiredMethod!1: @_TTWV14witness_tables15ConformingAssocS_9AssocReqtS_FS1_14requiredMethodUS1___fQPS1_FT_T_
// TABLE-NEXT: }
// TABLE-TESTABLE-LABEL: sil_witness_table ConformingAssoc: AssocReqt module witness_tables {
// TABLE-ALL-NEXT: method #AssocReqt.requiredMethod!1: @_TTWV14witness_tables15ConformingAssocS_9AssocReqtS_FS1_14requiredMethodUS1___fQPS1_FT_T_
// TABLE-ALL-NEXT: }
// SYMBOL: sil hidden [transparent] [thunk] @_TTWV14witness_tables15ConformingAssocS_9AssocReqtS_FS1_14requiredMethodUS1___fQPS1_FT_T_ : $@cc(witness_method) @thin (@in_guaranteed ConformingAssoc) -> ()
// SYMBOL-TESTABLE: sil [transparent] [thunk] @_TTWV14witness_tables15ConformingAssocS_9AssocReqtS_FS1_14requiredMethodUS1___fQPS1_FT_T_ : $@cc(witness_method) @thin (@in_guaranteed ConformingAssoc) -> ()
struct ConformingStruct : AnyProtocol {
typealias AssocType = SomeAssoc
@@ -88,6 +94,11 @@ func <~>(x: ConformingStruct, y: ConformingStruct) {}
// SYMBOL: sil hidden [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_FS1_16assocTypesMethodUS1__U_S_9AssocReqt__fQPS1_FT1xQS3_9AssocType1yQS3_13AssocWithReqt_T_ : $@cc(witness_method) @thin (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
// SYMBOL: sil hidden [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_ZFS1_12staticMethodUS1__U_S_9AssocReqt__fMQPS1_FT1xS3__T_ : $@cc(witness_method) @thin (@in ConformingStruct, @thick ConformingStruct.Type) -> ()
// SYMBOL: sil hidden [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_ZFS1_oi3ltgUS1__U_S_9AssocReqt__{{.*}} : $@cc(witness_method) @thin (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> ()
// SYMBOL-TESTABLE: sil [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_FS1_6methodUS1__U_S_9AssocReqt__fQPS1_FT1xVS_3Arg1yS3__T_ : $@cc(witness_method) @thin (Arg, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
// SYMBOL-TESTABLE: sil [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_FS1_7genericUS1__U_S_9AssocReqt__fQPS1_US_13ArchetypeReqt__FT1xQ_1yS3__T_ : $@cc(witness_method) @thin <A where A : ArchetypeReqt> (@in A, @in ConformingStruct, @in_guaranteed ConformingStruct) -> ()
// SYMBOL-TESTABLE: sil [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_FS1_16assocTypesMethodUS1__U_S_9AssocReqt__fQPS1_FT1xQS3_9AssocType1yQS3_13AssocWithReqt_T_ : $@cc(witness_method) @thin (@in SomeAssoc, @in ConformingAssoc, @in_guaranteed ConformingStruct) -> ()
// SYMBOL-TESTABLE: sil [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_ZFS1_12staticMethodUS1__U_S_9AssocReqt__fMQPS1_FT1xS3__T_ : $@cc(witness_method) @thin (@in ConformingStruct, @thick ConformingStruct.Type) -> ()
// SYMBOL-TESTABLE: sil [transparent] [thunk] @_TTWV14witness_tables16ConformingStructS_11AnyProtocolS_ZFS1_oi3ltgUS1__U_S_9AssocReqt__{{.*}} : $@cc(witness_method) @thin (@in ConformingStruct, @in ConformingStruct, @thick ConformingStruct.Type) -> ()
protocol AddressOnly {}

View File

@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend %s -O -emit-sil | FileCheck %s
// RUN: %target-swift-frontend %s -O -emit-sil -enable-testing | FileCheck -check-prefix=CHECK-TESTING %s
// Check if cycles are removed.
@@ -86,15 +87,30 @@ public func callTest() {
// CHECK-NOT: sil {{.*}}deadWitness
// CHECK-NOT: sil {{.*}}publicClassMethod
// CHECK-TESTING: sil {{.*}}inCycleA
// CHECK-TESTING: sil {{.*}}inCycleB
// CHECK-TESTING: sil {{.*}}deadMethod
// CHECK-TESTING: sil {{.*}}publicClassMethod
// CHECK-TESTING: sil {{.*}}deadWitness
// CHECK-LABEL: sil_vtable Base
// CHECK-NOT: deadMethod
// CHECK-TESTING-LABEL: sil_vtable Base
// CHECK-TESTING: deadMethod
// CHECK-LABEL: sil_vtable Derived
// CHECK-NOT: deadMethod
// CHECK-TESTING-LABEL: sil_vtable Derived
// CHECK-TESTING: deadMethod
// CHECK-LABEL: sil_witness_table hidden Adopt: Prot
// CHECK: deadWitness{{.*}} nil
// CHECK-TESTING-LABEL: sil_witness_table Adopt: Prot
// CHECK-TESTING: deadWitness{{.*}}: @{{.*}}deadWitness
// <rdar://problem/19267795> failable initializers that call noreturn function produces bogus diagnostics

View File

@@ -1,9 +1,11 @@
// RUN: %target-swift-frontend -O -emit-sil %s %S/Inputs/internal_func.swift | FileCheck %s
// RUN: %target-swift-frontend -O -enable-testing -emit-sil %s %S/Inputs/internal_func.swift | FileCheck -check-prefix=CHECK-TESTABLE %s
// Check that an internal function from another file is removed after it gets
// dead through inlining.
// CHECK-NOT: sil {{.*}}testfunc
// CHECK-TESTABLE: sil {{.*}}testfunc
public func caller_func() {
testfunc()

View File

@@ -1,4 +1,5 @@
// RUN: %target-swift-frontend -O -module-name devirt_default_case -disable-func-sig-opts -emit-sil %s | FileCheck %s
// RUN: %target-swift-frontend -O -module-name devirt_default_case -disable-func-sig-opts -emit-sil %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-NORMAL %s
// RUN: %target-swift-frontend -O -module-name devirt_default_case -disable-func-sig-opts -emit-sil -enable-testing %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-TESTABLE %s
@asmname("action")
func action(n:Int)->()
@@ -62,12 +63,14 @@ public func callOuter(x: Int) -> Int {
class Base3 {
@inline(never) func inner() { action(5)}
@inline(never) func middle() { inner() }
// Check that call to Base3.middle can be devirtualized
// Check that call to Base3.middle can be devirtualized when not compiling
// for testing.
//
// CHECK-LABEL: sil hidden [noinline] @_TFC19devirt_default_case5Base35outerfS0_FT_T_
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @_TFC19devirt_default_case5Base35outerfS0_FT_T_
// CHECK: function_ref @_TFC19devirt_default_caseP{{.*}}8Derived36middlefS0_FT_T_
// CHECK: function_ref @_TFC19devirt_default_case5Base36middlefS0_FT_T_
// CHECK-NOT: class_method
// CHECK-NOMRAL-NOT: class_method
// CHECK-TESTABLE: class_method %0 : $Base3, #Base3.middle!1
// CHECK: }
@inline(never) func outer() {
middle()
@@ -92,9 +95,10 @@ class E2 :C2 {}
func foo(a: A2) -> Int {
// Check that call to A2.f() can be devirualized.
//
// CHECK-LABEL: sil hidden [noinline] @_TF19devirt_default_case3fooFCS_2A2Si
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @_TF19devirt_default_case3fooFCS_2A2Si
// CHECK: function_ref @_TFC19devirt_default_case2A21ffS0_FT_Si
// CHECK-NOT: class_method
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %0 : $A2, #A2.f!1
// CHECK: }
return a.f()
}
@@ -115,10 +119,11 @@ class E3 :C3 {}
func foo(a: A3) -> Int {
// Check that call to A3.f() can be devirualized.
//
// CHECK-LABEL: sil hidden [noinline] @_TF19devirt_default_case3fooFCS_2A3Si
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @_TF19devirt_default_case3fooFCS_2A3Si
// CHECK: function_ref @_TFC19devirt_default_case2B31ffS0_FT_Si
// CHECK: function_ref @_TFC19devirt_default_case2A31ffS0_FT_Si
// CHECK-NOT: class_method
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %0 : $A3, #A3.f!1
// CHECK: }
return a.f()
}
@@ -132,10 +137,11 @@ class Base4 {
func test() {
// Check that call to foo() can be devirtualized
//
// CHECK-LABEL: sil hidden [noinline] @_TFC19devirt_default_case5Base44testfS0_FT_T_
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @_TFC19devirt_default_case5Base44testfS0_FT_T_
// CHECK: function_ref @_TFC19devirt_default_case8Derived43foofS0_FT_T_
// CHECK: function_ref @_TFC19devirt_default_case5Base43foofS0_FT_T_
// CHECK-NOT: class_method
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %0 : $Base4, #Base4.foo!1
// CHECK: }
foo()
}
@@ -178,7 +184,7 @@ class D6 : C6 {
func check_static_class_devirt(c: C6) -> Int {
// Check that C.bar() and D.bar() are devirtualized.
//
// CHECK-LABEL: sil hidden [noinline] @_TF19devirt_default_case25check_static_class_devirtFCS_2C6Si
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @_TF19devirt_default_case25check_static_class_devirtFCS_2C6Si
// CHECK: checked_cast_br [exact] %0 : $C6 to $D6
// CHECK: checked_cast_br [exact] %0 : $C6 to $C6
// CHECK: class_method
@@ -197,14 +203,16 @@ class B7 : A7 { @inline(never) override func foo() -> Bool { return true } }
// Check that it compiles without crashes and devirtualizes
// calls to A7.foo and B7.foo
//
// CHECK-LABEL: sil hidden [noinline] @_TF19devirt_default_case33check_call_on_downcasted_instanceFCS_2A7Sb
// CHECK-LABEL: sil{{( hidden)?}} [noinline] @_TF19devirt_default_case33check_call_on_downcasted_instanceFCS_2A7Sb
// CHECK: checked_cast_br
// CHECK-NOT: class_method
// CHECK: unconditional_checked_cast
// CHECK: function_ref @_TFC19devirt_default_case2B73foofS0_FT_Sb
// CHECK-NOT: class_method
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %{{[0-9]+}} : $B7, #B7.foo!1
// CHECK: function_ref @_TFC19devirt_default_case2A73foofS0_FT_Sb
// CHECK-NOT: class_method
// CHECK-NORMAL-NOT: class_method
// CHECK-TESTABLE: class_method %{{[0-9]+}} : $A7, #A7.foo!1
// CHECK: return
@inline(never)
func check_call_on_downcasted_instance(a: A7) -> Bool {