diff --git a/include/swift/SIL/SILDeclRef.h b/include/swift/SIL/SILDeclRef.h index 3d160f9f49e..cb0ff397206 100644 --- a/include/swift/SIL/SILDeclRef.h +++ b/include/swift/SIL/SILDeclRef.h @@ -576,6 +576,10 @@ struct SILDeclRef { /// for e.g a lazy variable getter. bool hasUserWrittenCode() const; + /// Returns true if this is a function that should be emitted because it is + /// accessible in the debugger. + bool shouldBeEmittedForDebugger() const; + /// Return the scope in which the parent class of a method (i.e. class /// containing this declaration) can be subclassed, returning NotApplicable if /// this is not a method, there is no such class, or the class cannot be diff --git a/lib/SIL/IR/SILDeclRef.cpp b/lib/SIL/IR/SILDeclRef.cpp index 23eddd23bf8..5890a4b4357 100644 --- a/lib/SIL/IR/SILDeclRef.cpp +++ b/lib/SIL/IR/SILDeclRef.cpp @@ -387,6 +387,39 @@ bool SILDeclRef::hasUserWrittenCode() const { llvm_unreachable("Unhandled case in switch!"); } +bool SILDeclRef::shouldBeEmittedForDebugger() const { + if (!isFunc()) + return false; + + if (getASTContext().SILOpts.OptMode != OptimizationMode::NoOptimization) + return false;; + + if (!getASTContext().SILOpts.ShouldFunctionsBePreservedToDebugger) + return false; + + if (getASTContext().LangOpts.hasFeature(Feature::Embedded)) + return false; + + ValueDecl *decl = getDecl(); + DeclAttributes &attrs = decl->getAttrs(); + if (attrs.hasSemanticsAttr("no.preserve.debugger")) + return false; + + if (getLinkage(ForDefinition) == SILLinkage::Shared) + return false; + + if (auto decl = getDecl()) + if (!decl->isImplicit()) + return true; + + // Synthesized getters are still callable in the debugger. + if (auto *accessor = dyn_cast_or_null(getFuncDecl())) { + return accessor->isSynthesized() && accessor->isGetterOrSetter(); + }; + + return false; +} + namespace { enum class LinkageLimit { /// No limit. diff --git a/lib/SILGen/SILGen.cpp b/lib/SILGen/SILGen.cpp index 449502b4bb7..68b5be7decb 100644 --- a/lib/SILGen/SILGen.cpp +++ b/lib/SILGen/SILGen.cpp @@ -1198,8 +1198,9 @@ void SILGenModule::emitOrDelayFunction(SILDeclRef constant) { auto emitAfter = lastEmittedFunction; // Implicit decls may be delayed if they can't be used externally. - auto linkage = constant.getLinkage(ForDefinition); - bool mayDelay = !constant.hasUserWrittenCode() && + auto linkage = constant.getLinkage(ForDefinition);; + bool mayDelay = !constant.shouldBeEmittedForDebugger() && + !constant.hasUserWrittenCode() && !constant.isDynamicallyReplaceable() && !isPossiblyUsedExternally(linkage, M.isWholeModule()); diff --git a/test/IRGen/preserve_for_debugger.swift b/test/IRGen/preserve_for_debugger.swift index 1bbac61a8a2..c9edbadfe1c 100644 --- a/test/IRGen/preserve_for_debugger.swift +++ b/test/IRGen/preserve_for_debugger.swift @@ -55,6 +55,8 @@ class Baz: Foo { struct Qux { @Bar(wrappedValue: Baz()) private var baz: Baz + // Baz instance that is never accessed. + @Bar(wrappedValue: Baz()) private var baz2: Baz func f() { print(self.baz) // break here @@ -64,3 +66,4 @@ let qux = Qux() qux.f() // CHECK: !DISubprogram(name: "baz.get" +// CHECK: !DISubprogram(name: "baz2.get"