diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 7f17f1f604a..2f624613999 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -2207,6 +2207,9 @@ public: return result; } + /// Determine whether this Decl has either Private or FilePrivate access. + bool isOutermostPrivateOrFilePrivateScope() const; + /// Returns the outermost DeclContext from which this declaration can be /// accessed, or null if the declaration is public. /// diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 3633ce6eb74..3ed397cb231 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -533,25 +533,6 @@ void ASTMangler::appendSymbolKind(SymbolKind SKind) { } } -/// Returns true if one of the ancestor DeclContexts of \p D is either marked -/// private or is a local context. -static bool isInPrivateOrLocalContext(const ValueDecl *D) { - const DeclContext *DC = D->getDeclContext(); - if (!DC->isTypeContext()) { - assert((DC->isModuleScopeContext() || DC->isLocalContext()) && - "unexpected context kind"); - return DC->isLocalContext(); - } - - auto *nominal = DC->getAsNominalTypeOrNominalTypeExtensionContext(); - if (nominal == nullptr) - return false; - - if (nominal->getFormalAccess() <= AccessLevel::FilePrivate) - return true; - return isInPrivateOrLocalContext(nominal); -} - static bool getUnnamedParamIndex(const ParameterList *ParamList, const ParamDecl *D, unsigned &UnnamedIndex) { @@ -593,11 +574,8 @@ static unsigned getUnnamedParamIndex(const ParamDecl *D) { } static StringRef getPrivateDiscriminatorIfNecessary(const ValueDecl *decl) { - if (!decl->hasAccess() || - decl->getFormalAccess() > AccessLevel::FilePrivate || - isInPrivateOrLocalContext(decl)) { + if (!decl->isOutermostPrivateOrFilePrivateScope()) return StringRef(); - } // Mangle non-local private declarations with a textual discriminator // based on their enclosing file. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 8c44db637ce..dc5a93f348b 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1433,6 +1433,34 @@ AbstractStorageDecl::getAccessStrategy(AccessSemantics semantics, llvm_unreachable("bad access semantics"); } +static bool hasPrivateOrFilePrivateFormalAccess(const ValueDecl *D) { + return D->hasAccess() && D->getFormalAccess() <= AccessLevel::FilePrivate; +} + +/// Returns true if one of the ancestor DeclContexts of this ValueDecl is either +/// marked private or fileprivate or is a local context. +static bool isInPrivateOrLocalContext(const ValueDecl *D) { + const DeclContext *DC = D->getDeclContext(); + if (!DC->isTypeContext()) { + assert((DC->isModuleScopeContext() || DC->isLocalContext()) && + "unexpected context kind"); + return DC->isLocalContext(); + } + + auto *nominal = DC->getAsNominalTypeOrNominalTypeExtensionContext(); + if (nominal == nullptr) + return false; + + if (hasPrivateOrFilePrivateFormalAccess(nominal)) + return true; + return isInPrivateOrLocalContext(nominal); +} + +bool ValueDecl::isOutermostPrivateOrFilePrivateScope() const { + return hasPrivateOrFilePrivateFormalAccess(this) && + !isInPrivateOrLocalContext(this); +} + bool AbstractStorageDecl::hasFixedLayout() const { // If we're in a nominal type, just query the type. auto *dc = getDeclContext(); diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index d469b20f042..230351c76bb 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1395,6 +1395,19 @@ private: return nullptr; } + /// The private discriminator is represented as an inline namespace. + llvm::DIScope *getFilePrivateScope(llvm::DIScope *Parent, TypeDecl *Decl, + DeclContext *Context) { + // Retrieve the private discriminator. + if (auto *SF = Context->getParentSourceFile()) { + auto PrivateDiscriminator = SF->getPrivateDiscriminator(); + if (!PrivateDiscriminator.empty()) + return DBuilder.createNameSpace(Parent, PrivateDiscriminator.str(), + /*ExportSymbols=*/true); + } + llvm_unreachable("unknown private discriminator"); + } + llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy) { // Is this an empty type? if (DbgTy.isNull()) @@ -1438,6 +1451,13 @@ private: } if (!Scope) Scope = getOrCreateContext(Context); + + // Scope outermost fileprivate decls in an inline private discriminator + // namespace. + if (auto *Decl = DbgTy.getDecl()) + if (Context && Decl->isOutermostPrivateOrFilePrivateScope()) + Scope = getFilePrivateScope(Scope, Decl, Context); + llvm::DIType *DITy = createType(DbgTy, MangledName, Scope, getFile(Scope)); // Incrementally build the DIRefMap. @@ -1518,9 +1538,9 @@ IRGenDebugInfoImpl::IRGenDebugInfoImpl(const IRGenOptions &Opts, CU_Nodes->addOperand(*CU); // Create a module for the current compile unit. + auto *MDecl = IGM.getSwiftModule(); llvm::sys::path::remove_filename(AbsMainFile); - MainModule = getOrCreateModule(IGM.getSwiftModule(), TheCU, Opts.ModuleName, - AbsMainFile); + MainModule = getOrCreateModule(MDecl, TheCU, Opts.ModuleName, AbsMainFile); DBuilder.createImportedModule(MainFile, MainModule, MainFile, 0); // Macro definitions that were defined by the user with "-Xcc -D" on the diff --git a/test/DebugInfo/PrivateDiscriminator.swift b/test/DebugInfo/PrivateDiscriminator.swift index 1db03e17827..c706f5354c6 100644 --- a/test/DebugInfo/PrivateDiscriminator.swift +++ b/test/DebugInfo/PrivateDiscriminator.swift @@ -1,25 +1,57 @@ // Private discriminators should only be emitted for multi-file projects. -// RUN: %target-swift-frontend -emit-ir %s -g -o - | %FileCheck --check-prefix=SINGLE %s +// RUN: %target-swift-frontend -emit-ir %s -g -o - \ +// RUN: | %FileCheck --check-prefix=SINGLE %s // SINGLE-NOT: !DICompileUnit({{.*}}-private-discriminator -// RUN: %target-swift-frontend %S/../Inputs/empty.swift -primary-file %s -emit-ir -g | %FileCheck %s +// RUN: %target-swift-frontend %S/../Inputs/empty.swift -primary-file %s \ +// RUN: -emit-ir -g | %FileCheck %s // CHECK: !DICompileUnit({{.*}}flags: {{[^,]*}}-private-discriminator [[DISCRIMINATOR:_[A-Z0-9]+]] +// CHECK: ![[MOD:.*]] = !DIModule(scope: null, +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "InA", +// CHECK-SAME: scope: ![[A:[0-9]+]], +// CHECK: ![[A]] = !DICompositeType(tag: DW_TAG_structure_type, name: "A", +// CHECK-SAME: scope: ![[NS:[0-9]+]] +// CHECK: !DINamespace(name: "[[DISCRIMINATOR]]", +// CHECK-SAME: scope: ![[OUTER:[0-9]+]], exportSymbols: true) +// CHECK: ![[OUTER]] = !DICompositeType(tag: DW_TAG_structure_type, +// CHECK-SAME: name: "Outer", +// CHECK-SAME: scope: ![[MOD]], func markUsed(_ t: T) {} -private class A { - init(val : Int64) { member = val } - private let member : Int64 - // CHECK: !DISubprogram(name: "getMember" - // CHECK-SAME: linkageName: "{{[^"]*}}[[DISCRIMINATOR]] - // CHECK-SAME: line: [[@LINE+2]] - // CHECK-SAME: isLocal: true, isDefinition: true - private func getMember() -> Int64 { return member } - func getVal() -> Int64 { return getMember() } +public class Outer { + fileprivate class A { + fileprivate struct InA { + let i : Int64 + init(_ val : Int64) { i = val } + } + + init(val : Int64) { member = InA(val) } + fileprivate let member : InA + // CHECK: !DISubprogram(name: "getMember" + // CHECK-SAME: linkageName: "{{[^"]*}}[[DISCRIMINATOR]] + // CHECK-SAME: line: [[@LINE+2]] + // CHECK-SAME: isLocal: true, isDefinition: true + fileprivate func getMember() -> Int64 { return member.i } + } } -func f() { - let a = A(val: 42) - markUsed(a.getVal()) +// CHECK: ![[G:[0-9]+]] = distinct !DISubprogram(name: "g", +// CHECK-SAME: scope: ![[MOD]] +fileprivate func g() -> Int64 { + // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "InG", + // CHECK-SAME: scope: ![[G]], + struct InG { + let i : Int64 + init(_ val : Int64) { i = val } + } + + return InG(42).i +} + +// CHECK: distinct !DISubprogram(name: "f", {{.*}}, scope: ![[MOD]] +public func f() { + let a = Outer.A(val: g()) + markUsed(a) }