Skip to content

Commit e0ce718

Browse files
committed
[DebugInfo] Fix handling of @_originallyDefinedIn types
Emit an imported declaration for @_originallyDefinedIn under the real module that these types live in. This patch also changes the mangling for the debugger to respect @_originallyDefinedIn, and fixes a bug where @_originallyDefinedIn that should be ignored was still being used when mangling. rdar://137146961
1 parent f9424ce commit e0ce718

8 files changed

+193
-44
lines changed

lib/AST/ASTMangler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -717,7 +717,7 @@ std::string ASTMangler::mangleTypeForDebugger(Type Ty, GenericSignature sig) {
717717
"mangling type for debugger", Ty);
718718

719719
DWARFMangling = true;
720-
RespectOriginallyDefinedIn = false;
720+
RespectOriginallyDefinedIn = true;
721721
OptimizeProtocolNames = false;
722722
beginMangling();
723723

lib/AST/Decl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ const ExternalSourceLocs *Decl::getSerializedLocs() const {
978978
StringRef Decl::getAlternateModuleName() const {
979979
for (auto *Att: Attrs) {
980980
if (auto *OD = dyn_cast<OriginallyDefinedInAttr>(Att)) {
981-
if (OD->isActivePlatform(getASTContext())) {
981+
if (!OD->isInvalid() && OD->isActivePlatform(getASTContext())) {
982982
return OD->OriginalModuleName;
983983
}
984984
}

lib/IRGen/IRGenDebugInfo.cpp

Lines changed: 130 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "IRGenDebugInfo.h"
18+
#include "DebugTypeInfo.h"
1819
#include "GenEnum.h"
1920
#include "GenOpaque.h"
2021
#include "GenStruct.h"
@@ -23,13 +24,17 @@
2324
#include "IRBuilder.h"
2425
#include "swift/AST/ASTDemangler.h"
2526
#include "swift/AST/ASTMangler.h"
27+
#include "swift/AST/Attr.h"
28+
#include "swift/AST/Decl.h"
2629
#include "swift/AST/Expr.h"
2730
#include "swift/AST/GenericEnvironment.h"
2831
#include "swift/AST/IRGenOptions.h"
2932
#include "swift/AST/Module.h"
3033
#include "swift/AST/ModuleLoader.h"
34+
#include "swift/AST/ParameterList.h"
3135
#include "swift/AST/Pattern.h"
3236
#include "swift/AST/TypeDifferenceVisitor.h"
37+
#include "swift/AST/Types.h"
3338
#include "swift/Basic/Assertions.h"
3439
#include "swift/Basic/Compiler.h"
3540
#include "swift/Basic/SourceManager.h"
@@ -61,13 +66,15 @@
6166
#include "llvm/IR/DebugInfo.h"
6267
#include "llvm/IR/IntrinsicInst.h"
6368
#include "llvm/IR/Module.h"
69+
#include "llvm/Support/Casting.h"
6470
#include "llvm/Support/CommandLine.h"
6571
#include "llvm/Support/Debug.h"
6672
#include "llvm/Support/FileSystem.h"
6773
#include "llvm/Support/MemoryBuffer.h"
6874
#include "llvm/Support/Path.h"
6975
#include "llvm/Support/raw_ostream.h"
7076
#include "llvm/Transforms/Utils/Local.h"
77+
#include <cstddef>
7178

7279
#define DEBUG_TYPE "debug-info"
7380

@@ -150,6 +157,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
150157
llvm::DenseMap<const void *, llvm::TrackingMDNodeRef> DIModuleCache;
151158
llvm::StringMap<llvm::TrackingMDNodeRef> DIFileCache;
152159
llvm::StringMap<llvm::TrackingMDNodeRef> RuntimeErrorFnCache;
160+
llvm::StringSet<> OriginallyDefinedInTypes;
153161
TrackingDIRefMap DIRefMap;
154162
TrackingDIRefMap InnerTypeCache;
155163
/// \}
@@ -1026,9 +1034,12 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo {
10261034
Mangle::ASTMangler Mangler;
10271035
std::string Result = Mangler.mangleTypeForDebugger(Ty, Sig);
10281036

1037+
bool IsTypeOriginallyDefinedIn =
1038+
containsOriginallyDefinedIn(DbgTy.getType());
10291039
// TODO(https://github.com/apple/swift/issues/57699): We currently cannot round trip some C++ types.
1040+
// There's no way to round trip when respecting @_originallyDefinedIn for a type.
10301041
if (!Opts.DisableRoundTripDebugTypes &&
1031-
!Ty->getASTContext().LangOpts.EnableCXXInterop) {
1042+
!Ty->getASTContext().LangOpts.EnableCXXInterop && !IsTypeOriginallyDefinedIn) {
10321043
// Make sure we can reconstruct mangled types for the debugger.
10331044
auto &Ctx = Ty->getASTContext();
10341045
Type Reconstructed = Demangle::getTypeForMangling(Ctx, Result, Sig);
@@ -1506,7 +1517,7 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
15061517
/// anchor any typedefs that may appear in parameters so they can be
15071518
/// resolved in the debugger without needing to query the Swift module.
15081519
llvm::DINodeArray
1509-
collectGenericParams(NominalOrBoundGenericNominalType *BGT) {
1520+
collectGenericParams(NominalOrBoundGenericNominalType *BGT, bool AsForwardDeclarations = false) {
15101521

15111522
// Collect the generic args from the type and its parent.
15121523
std::vector<Type> GenericArgs;
@@ -1521,7 +1532,8 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
15211532
SmallVector<llvm::Metadata *, 16> TemplateParams;
15221533
for (auto Arg : GenericArgs) {
15231534
DebugTypeInfo ParamDebugType;
1524-
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes)
1535+
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes &&
1536+
!AsForwardDeclarations)
15251537
// For the DwarfTypes level don't generate just a forward declaration
15261538
// for the generic type parameters.
15271539
ParamDebugType = DebugTypeInfo::getFromTypeInfo(
@@ -1789,26 +1801,6 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
17891801
}
17901802

17911803
llvm::DIType *SpecificationOf = nullptr;
1792-
if (auto *TypeDecl = DbgTy.getType()->getNominalOrBoundGenericNominal()) {
1793-
// If this is a nominal type that has the @_originallyDefinedIn attribute,
1794-
// IRGenDebugInfo emits a forward declaration of the type as a child
1795-
// of the original module, and the type with a specification pointing to
1796-
// the forward declaraation. We do this so LLDB has enough information to
1797-
// both find the type in reflection metadata (the parent module name) and
1798-
// find it in the swiftmodule (the module name in the type mangled name).
1799-
if (auto Attribute =
1800-
TypeDecl->getAttrs().getAttribute<OriginallyDefinedInAttr>()) {
1801-
auto Identifier = IGM.getSILModule().getASTContext().getIdentifier(
1802-
Attribute->OriginalModuleName);
1803-
1804-
void *Key = (void *)Identifier.get();
1805-
auto InnerScope =
1806-
getOrCreateModule(Key, TheCU, Attribute->OriginalModuleName, {});
1807-
SpecificationOf = DBuilder.createForwardDecl(
1808-
llvm::dwarf::DW_TAG_structure_type, TypeDecl->getNameStr(),
1809-
InnerScope, File, 0, llvm::dwarf::DW_LANG_Swift, 0, 0);
1810-
}
1811-
}
18121804

18131805
// Here goes!
18141806
switch (BaseTy->getKind()) {
@@ -2338,6 +2330,106 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
23382330
}
23392331
}
23402332

2333+
/// Returns true if the type's mangled name is affected by an
2334+
/// @_originallyDefinedIn annotation. This annotation can be on the type
2335+
/// itself, one of its generic arguments, etc.
2336+
bool containsOriginallyDefinedIn(Type T) {
2337+
if (auto *MT = llvm::dyn_cast<MetatypeType>(T))
2338+
if (containsOriginallyDefinedIn(MT->getInstanceType()))
2339+
return true;
2340+
;
2341+
2342+
auto *TypeDecl = T->getNominalOrBoundGenericNominal();
2343+
if (!TypeDecl)
2344+
return false;
2345+
2346+
// Find the outermost type, since only those can be annotated with
2347+
// @_originallyDefinedIn.
2348+
NominalTypeDecl *ParentDecl = TypeDecl;
2349+
while (llvm::isa_and_nonnull<NominalTypeDecl>(ParentDecl->getParent()))
2350+
ParentDecl = llvm::cast<NominalTypeDecl>(ParentDecl->getParent());
2351+
2352+
if (ParentDecl->getAttrs().hasAttribute<OriginallyDefinedInAttr>())
2353+
return true;
2354+
2355+
// If the type is a bound generic, the type of the substituted generic
2356+
// arguments might be annotated with @_originallyDefinedIn.
2357+
if (auto *BGT = llvm::dyn_cast<BoundGenericType>(T))
2358+
for (auto &Arg : BGT->getGenericArgs())
2359+
if (containsOriginallyDefinedIn(Arg))
2360+
return true;
2361+
2362+
// A typealias inside a function mentions the function's signature, so check
2363+
// if any types in the generic signature are annotated with
2364+
// @_originallyDefinedIn.
2365+
if (auto *TAT = llvm::dyn_cast<TypeAliasType>(T)) {
2366+
auto D = TAT->getDecl()->getDeclContext();
2367+
if (auto AFD = llvm::dyn_cast<AbstractFunctionDecl>(D)) {
2368+
for (auto &Param : *AFD->getParameters())
2369+
if (containsOriginallyDefinedIn(Param->getInterfaceType()))
2370+
return true;
2371+
2372+
for (auto &Req : AFD->getGenericSignature().getRequirements())
2373+
if (containsOriginallyDefinedIn(Req.getFirstType()) ||
2374+
containsOriginallyDefinedIn(Req.getSecondType()))
2375+
return true;
2376+
2377+
if (auto FD = llvm::dyn_cast<FuncDecl>(D))
2378+
if (containsOriginallyDefinedIn(FD->getResultInterfaceType()))
2379+
return true;
2380+
}
2381+
}
2382+
2383+
return false;
2384+
}
2385+
2386+
/// Returns the decl of the type's parent chain annotated by
2387+
/// @_originallyDefinedIn. Returns null if no type is annotated.
2388+
NominalTypeDecl *getDeclAnnotatedByOriginallyDefinedIn(DebugTypeInfo DbgTy) {
2389+
auto Type = DbgTy.getType();
2390+
auto *TypeDecl = Type->getNominalOrBoundGenericNominal();
2391+
if (!TypeDecl)
2392+
return nullptr;
2393+
2394+
// Find the outermost type, since only those can have @_originallyDefinedIn
2395+
// attached to them.
2396+
NominalTypeDecl *ParentDecl = TypeDecl;
2397+
while (llvm::isa_and_nonnull<NominalTypeDecl>(ParentDecl->getParent()))
2398+
ParentDecl = llvm::cast<NominalTypeDecl>(ParentDecl->getParent());
2399+
2400+
if (ParentDecl->getAttrs().hasAttribute<OriginallyDefinedInAttr>())
2401+
return ParentDecl;;
2402+
2403+
return nullptr;
2404+
}
2405+
2406+
/// If this is a nominal type that has the @_originallyDefinedIn
2407+
/// attribute, IRGenDebugInfo emits an imported declaration of the type as
2408+
/// a child of the real module. We do this so LLDB has enough
2409+
/// information to both find the type in reflection metadata (the module name
2410+
/// in the type's mangled name), and find it in the swiftmodule (the type's
2411+
/// imported declaration's parent module name).
2412+
void handleOriginallyDefinedIn(DebugTypeInfo DbgTy, llvm::DIType *DITy,
2413+
StringRef MangledName, llvm::DIFile *File) {
2414+
if (OriginallyDefinedInTypes.contains(MangledName))
2415+
return;
2416+
2417+
// Force the generation of the generic type parameters as forward
2418+
// declarations, as those types might be annotated with
2419+
// @_originallyDefinedIn.
2420+
if (auto *BoundDecl = llvm::dyn_cast<BoundGenericType>(DbgTy.getType()))
2421+
collectGenericParams(BoundDecl, /*AsForwardDeclarations=*/true);
2422+
2423+
NominalTypeDecl *OriginallyDefinedInDecl = getDeclAnnotatedByOriginallyDefinedIn(DbgTy);
2424+
if (!OriginallyDefinedInDecl)
2425+
return;
2426+
2427+
// Emit the imported declaration under the real swiftmodule the type lives on.
2428+
auto RealModule = getOrCreateContext(OriginallyDefinedInDecl->getParent());
2429+
DBuilder.createImportedDeclaration(RealModule, DITy, File, 0, MangledName);
2430+
OriginallyDefinedInTypes.insert(MangledName);
2431+
}
2432+
23412433
llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy,
23422434
llvm::DIScope *Scope = nullptr) {
23432435
// Is this an empty type?
@@ -2382,7 +2474,18 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
23822474
ClangDecl = AliasDecl->getClangDecl();
23832475
} else if (auto *ND = DbgTy.getType()->getNominalOrBoundGenericNominal()) {
23842476
TypeDecl = ND;
2385-
Context = ND->getParent();
2477+
// If this is an originally defined in type, we want to emit this type's scope
2478+
// to be the ABI module.
2479+
if (auto Attribute =
2480+
ND->getAttrs().getAttribute<OriginallyDefinedInAttr>()) {
2481+
auto Identifier = IGM.getSILModule().getASTContext().getIdentifier(
2482+
Attribute->OriginalModuleName);
2483+
void *Key = (void *)Identifier.get();
2484+
Scope =
2485+
getOrCreateModule(Key, TheCU, Attribute->OriginalModuleName, {});
2486+
} else {
2487+
Context = ND->getParent();
2488+
}
23862489
ClangDecl = ND->getClangDecl();
23872490
} else if (auto BNO = dyn_cast<BuiltinType>(DbgTy.getType())) {
23882491
Context = BNO->getASTContext().TheBuiltinModule;
@@ -2431,6 +2534,8 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
24312534
FwdDeclTypes.emplace_back(
24322535
std::piecewise_construct, std::make_tuple(MangledName),
24332536
std::make_tuple(static_cast<llvm::Metadata *>(FwdDecl)));
2537+
2538+
handleOriginallyDefinedIn(DbgTy, FwdDecl, MangledName, getFile(Scope));
24342539
return FwdDecl;
24352540
}
24362541
llvm::DIType *DITy = createType(DbgTy, MangledName, Scope, getFile(Scope));
@@ -2459,6 +2564,7 @@ createSpecializedStructOrClassType(NominalOrBoundGenericNominalType *Type,
24592564
// Store it in the cache.
24602565
DITypeCache.insert({DbgTy.getType(), llvm::TrackingMDNodeRef(DITy)});
24612566

2567+
handleOriginallyDefinedIn(DbgTy, DITy, MangledName, getFile(Scope));
24622568
return DITy;
24632569
}
24642570
};
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
@available(macOS 10, *)
2-
@_originallyDefinedIn(module: "Barn", macOS 10.1) public struct Horse {}
2+
@_originallyDefinedIn(module: "Barn", macOS 10.1)
3+
public struct Horse {
4+
public init() {}
5+
}
6+
7+
@available(macOS 10, *)
8+
@_originallyDefinedIn(module: "Barn", macOS 10.1) public class Cow {}

test/DebugInfo/local_type_originally_defined_in.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,19 @@ public func localTypeAliasTest(horse: Horse) {
1313

1414
let info = UnsafeMutablePointer<A>.allocate(capacity: 1)
1515
_ = info
16-
}
16+
}
17+
18+
public func localTypeAliasTest() -> Horse {
19+
typealias A = Int
20+
21+
let info = UnsafeMutablePointer<A>.allocate(capacity: 1)
22+
_ = info
23+
return Horse()
24+
}
25+
26+
public func localTypeAliasTestGeneric<T: Cow>(cow: T) {
27+
typealias A = Int
28+
29+
let info = UnsafeMutablePointer<A>.allocate(capacity: 1)
30+
_ = info
31+
}

test/DebugInfo/module_abi_name.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
class SomeClass {}
44
// CHECK: DICompositeType(tag: DW_TAG_structure_type, name: "SomeClass",{{.*}}runtimeLang: DW_LANG_Swift, identifier: "$s7Goodbye9SomeClassCD"
55

6-
@available(macOS 10.13, *)
7-
@_originallyDefinedIn(module: "ThirdModule", OSX 10.12)
8-
class DefinedElsewhere {}
9-
// CHECK: DICompositeType(tag: DW_TAG_structure_type, name: "DefinedElsewhere",{{.*}}runtimeLang: DW_LANG_Swift, identifier: "$s7Goodbye16DefinedElsewhereCD")
6+
@available(macOS 1.0, *)
7+
@_originallyDefinedIn(module: "ThirdModule", OSX 2.0)
8+
public class DefinedElsewhere {}
9+
// CHECK: DICompositeType(tag: DW_TAG_structure_type, name: "DefinedElsewhere",{{.*}}runtimeLang: DW_LANG_Swift, identifier: "$s11ThirdModule16DefinedElsewhereCD")
1010

1111
let v1 = SomeClass()
1212
let v2 = DefinedElsewhere()
Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,36 @@
11
// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s
22

3-
@_originallyDefinedIn(
4-
module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0)
5-
@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *)
6-
public struct A {
7-
let i = 10
8-
}
3+
@_originallyDefinedIn(
4+
module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0)
5+
@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *)
6+
public struct A {
7+
let i = 10
8+
}
99

10-
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "A",{{.*}}identifier: "$s21originally_defined_in1AVD",{{.*}}specification: ![[S1:[0-9]+]]
11-
// CHECK: [[S1]] = !DICompositeType(tag: DW_TAG_structure_type, name: "A", scope: ![[S2:[0-9]+]]
12-
// CHECK: [[S2]] = !DIModule({{.*}}name: "Other"
10+
@_originallyDefinedIn(
11+
module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0)
12+
@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *)
13+
public struct B {
14+
let i = 10
15+
}
16+
17+
// Test that a type with an invalid @_originallyDefinedIn does not change the mangled name.
18+
@_originallyDefinedIn(
19+
module: "Other", iOS 2.0, macOS 2.0, tvOS 2.0, watchOS 2.0)
20+
@available(iOS 1.0, macOS 1.0, tvOS 1.0, watchOS 1.0, *)
21+
private struct Invalid {
22+
let i = 20
23+
}
24+
25+
// CHECK: ![[MOD:[0-9]+]] = !DIModule(scope: null, name: "originally_defined_in"
26+
//
27+
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "A",{{.*}}scope: ![[S:[0-9]+]]{{.*}}identifier: "$s5Other1AVD"
28+
// CHECK: [[S]] = !DIModule({{.*}}name: "Other"
29+
30+
// CHECK: DICompositeType(tag: DW_TAG_structure_type, name: "Invalid",{{.*}}identifier: "$s21originally_defined_in
31+
32+
// CHECK: !DIImportedEntity(tag: DW_TAG_imported_declaration, name: "$s5Other1AVD",{{.*}}scope: ![[MOD]]
1333

1434
let a = A()
35+
let b = B.self
36+
private let i = Invalid()

test/Runtime/demangleToMetadataMovedSymbols.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,17 @@ let DemangleToMetadataMovedSymbolsTests = TestSuite("DemangleToMetadataMovedSymb
1212

1313
@available(OSX 10.9, *)
1414
@_originallyDefinedIn(module: "foo", OSX 10.13)
15-
struct MovedS {
15+
public struct MovedS {
1616
struct Nested { }
1717
}
1818

1919
@available(OSX 10.9, *)
2020
@_originallyDefinedIn(module: "foo", OSX 10.13)
21-
enum MovedE { case e }
21+
public enum MovedE { case e }
2222

2323
@available(OSX 10.9, *)
2424
@_originallyDefinedIn(module: "bar", OSX 10.13)
25-
class MovedC {}
25+
public class MovedC {}
2626

2727
DemangleToMetadataMovedSymbolsTests.test("Moved Nominals") {
2828
// Simple Struct

0 commit comments

Comments
 (0)