[Debug Info] Emit -gdwarf-types debug info for Builtin.FixedArray<>

This commit also changes how specialized types are being emitted. Previously we
would not emitthe detailed member information in the specialized type itself,
and instead rely on the fact that it was present in the unspecialized type,
however, this wold prevent us from emitting any bound generic members, so we're
now emitting the members in both variants of the type.

This uncovered a with type aliases that this commit also addresses: Because we
don't canonicalize types prior to caching in order to preserve type sugar,
alternative representations of recursive types (with one or more levels of
recursion unfolded) could create potential infinite chains of types. This is
addressed by checking whether a sugared type has an already emitted canonical
representation first, and if yes, creating a typedef node pointing directly to
it.

The donwside of doing this is that it can lead to the disappearnce of type
aliases definitions when they are used as parameters in bound generic
types. However, we still preserve that a type was `MyClass<MyAlias>`. We just
might have a typedef pointing director from `MyClass<MyAlias>` ->
`MyClass<CanonicalType>`.

rdar://144315592
This commit is contained in:
Adrian Prantl
2025-02-14 11:37:50 -08:00
parent b455e60204
commit fcbebc51c7
10 changed files with 268 additions and 116 deletions

View File

@@ -191,6 +191,8 @@ LLVM_DUMP_METHOD void DebugTypeInfo::dump() const {
std::optional<CompletedDebugTypeInfo>
CompletedDebugTypeInfo::getFromTypeInfo(swift::Type Ty, const TypeInfo &Info,
IRGenModule &IGM) {
if (!Ty || Ty->hasTypeParameter())
return {};
auto *StorageType = IGM.getStorageTypeForUnlowered(Ty);
std::optional<uint64_t> SizeInBits;
if (StorageType->isSized())

View File

@@ -458,11 +458,15 @@ private:
/// Strdup S using the bump pointer.
StringRef BumpAllocatedString(std::string S) {
if (S.empty())
return {};
return BumpAllocatedString(S.c_str(), S.length());
}
/// Strdup StringRef S using the bump pointer.
StringRef BumpAllocatedString(StringRef S) {
if (S.empty())
return {};
return BumpAllocatedString(S.data(), S.size());
}
@@ -980,10 +984,14 @@ private:
return SizeInBits;
}
StringRef getMangledName(DebugTypeInfo DbgTy) {
struct MangledNames {
StringRef Sugared, Canonical;
};
MangledNames getMangledName(DebugTypeInfo DbgTy) {
if (DbgTy.isMetadataType())
return MetadataTypeDeclCache.find(DbgTy.getDecl()->getName().str())
->getKey();
return {{},
MetadataTypeDeclCache.find(DbgTy.getDecl()->getName().str())
->getKey()};
// This is a bit of a hack. We need a generic signature to use for mangling.
// If we started with an interface type, just use IGM.getCurGenericContext(),
@@ -1032,7 +1040,15 @@ private:
IGM.getSILModule());
Mangle::ASTMangler Mangler(IGM.Context);
std::string Result = Mangler.mangleTypeForDebugger(Ty, Sig);
std::string SugaredName, CanonicalName;
SugaredName = Mangler.mangleTypeForDebugger(Ty, Sig);
CanType CanTy = Ty->getCanonicalType();
if (CanTy.getPointer() != Ty.getPointer()) {
CanonicalName = Mangler.mangleTypeForDebugger(CanTy, Sig);
if (SugaredName == CanonicalName)
CanonicalName.clear();
}
bool IsTypeOriginallyDefinedIn =
containsOriginallyDefinedIn(DbgTy.getType());
@@ -1042,9 +1058,10 @@ private:
!Ty->getASTContext().LangOpts.EnableCXXInterop && !IsTypeOriginallyDefinedIn) {
// Make sure we can reconstruct mangled types for the debugger.
auto &Ctx = Ty->getASTContext();
Type Reconstructed = Demangle::getTypeForMangling(Ctx, Result, Sig);
Type Reconstructed = Demangle::getTypeForMangling(Ctx, SugaredName, Sig);
if (!Reconstructed) {
llvm::errs() << "Failed to reconstruct type for " << Result << "\n";
llvm::errs() << "Failed to reconstruct type for " << SugaredName
<< "\n";
llvm::errs() << "Original type:\n";
Ty->dump(llvm::errs());
if (Sig)
@@ -1059,7 +1076,8 @@ private:
!equalWithoutExistentialTypes(Reconstructed, Ty) &&
!EqualUpToClangTypes().check(Reconstructed, Ty)) {
// [FIXME: Include-Clang-type-in-mangling] Remove second check
llvm::errs() << "Incorrect reconstructed type for " << Result << "\n";
llvm::errs() << "Incorrect reconstructed type for " << SugaredName
<< "\n";
llvm::errs() << "Original type:\n";
Ty->dump(llvm::errs());
llvm::errs() << "Reconstructed type:\n";
@@ -1073,7 +1091,12 @@ private:
}
}
return BumpAllocatedString(Result);
// Only return a dedicated sugared name if it's different from the canonical
// one.
if (CanonicalName.empty())
std::swap(SugaredName, CanonicalName);
return {BumpAllocatedString(SugaredName),
BumpAllocatedString(CanonicalName)};
}
llvm::DIDerivedType *createMemberType(DebugTypeInfo DbgTy, StringRef Name,
@@ -1119,24 +1142,22 @@ private:
return FwdDecl;
}
llvm::DICompositeType *
createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl,
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits,
llvm::DINode::DIFlags Flags, llvm::DIType *DerivedFrom,
unsigned RuntimeLang, StringRef UniqueID) {
llvm::DICompositeType *createStructType(
NominalOrBoundGenericNominalType *Type, NominalTypeDecl *Decl,
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
unsigned SizeInBits, unsigned AlignInBits, llvm::DINode::DIFlags Flags,
StringRef MangledName, llvm::DIType *SpecificationOf = nullptr) {
StringRef Name = Decl->getName().str();
auto FwdDecl = createTemporaryReplaceableForwardDecl(
DbgTy.getType(), Scope, File, Line, SizeInBits, AlignInBits, Flags,
UniqueID, Name);
Type, Scope, File, Line, SizeInBits, AlignInBits, Flags, MangledName,
Name);
// Collect the members.
SmallVector<llvm::Metadata *, 16> Elements;
unsigned OffsetInBits = 0;
for (VarDecl *VD : Decl->getStoredProperties()) {
auto memberTy = DbgTy.getType()->getTypeOfMember(VD);
auto memberTy = Type->getTypeOfMember(VD);
if (auto DbgTy = CompletedDebugTypeInfo::getFromTypeInfo(
VD->getInterfaceType(),
memberTy,
IGM.getTypeInfoForUnlowered(
IGM.getSILTypes().getAbstractionPattern(VD), memberTy),
IGM))
@@ -1145,24 +1166,25 @@ private:
else
// Without complete type info we can only create a forward decl.
return DBuilder.createForwardDecl(
llvm::dwarf::DW_TAG_structure_type, UniqueID, Scope, File, Line,
llvm::dwarf::DW_TAG_structure_type, MangledName, Scope, File, Line,
llvm::dwarf::DW_LANG_Swift, SizeInBits, 0);
}
auto DITy = DBuilder.createStructType(
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, DerivedFrom,
DBuilder.getOrCreateArray(Elements), RuntimeLang, nullptr, UniqueID);
llvm::DINodeArray BoundParams = collectGenericParams(Type);
auto DITy = createStruct(
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, MangledName,
DBuilder.getOrCreateArray(Elements), BoundParams, SpecificationOf);
DBuilder.replaceTemporary(std::move(FwdDecl), DITy);
return DITy;
}
/// Creates debug info for a generic struct or class with archetypes (e.g.:
/// Pair<τ_0_0, τ_0_1>). For types with unsubstituted generic type parameters,
/// debug info generation doesn't attempt to emit the size and aligment of
/// the type, as in the general case those are all dependent on substituting
/// the type parameters in (some exceptions exist, like generic types that are
/// class constrained). It also doesn't attempt to emit the offset of the
/// members for the same reason.
/// debug info generation doesn't attempt to emit the size and aligment of the
/// type, as in the general case those are all dependent on substituting the
/// type parameters in (some exceptions exist, like generic types that are
/// class constrained). It also doesn't attempt to emit the members for the
/// same reason.
llvm::DICompositeType *createUnsubstitutedGenericStructOrClassType(
DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type UnsubstitutedType,
llvm::DIScope *Scope, llvm::DIFile *File, unsigned Line,
@@ -1267,6 +1289,8 @@ private:
auto *Decl = Type->getNominalOrBoundGenericNominal();
if (!Decl)
return nullptr;
// This temporary forward decl seems to be redundant. Can it be removed?
StringRef Name = Decl->getName().str();
auto FwdDecl = createTemporaryReplaceableForwardDecl(
Type, Scope, File, Line, SizeInBits, AlignInBits, Flags, MangledName,
@@ -1298,11 +1322,10 @@ private:
}
}
// Create the substituted type.
auto *OpaqueType =
createOpaqueStruct(Scope, Decl ? Decl->getNameStr() : "", File, Line,
SizeInBits, AlignInBits, Flags, MangledName,
collectGenericParams(Type), UnsubstitutedDITy);
DBuilder.replaceTemporary(std::move(FwdDecl), OpaqueType);
createStructType(Type, Decl, Scope, File, Line, SizeInBits, AlignInBits,
Flags, MangledName, UnsubstitutedDITy);
return OpaqueType;
}
@@ -1711,22 +1734,31 @@ private:
return DITy;
}
llvm::DICompositeType *
createStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File,
unsigned Line, unsigned SizeInBits, unsigned AlignInBits,
llvm::DINode::DIFlags Flags, StringRef MangledName,
llvm::DINodeArray Elements, llvm::DINodeArray BoundParams,
llvm::DIType *SpecificationOf) {
auto StructType = DBuilder.createStructType(
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags,
/* DerivedFrom */ nullptr, Elements, llvm::dwarf::DW_LANG_Swift,
nullptr, MangledName, SpecificationOf);
if (BoundParams)
DBuilder.replaceArrays(StructType, nullptr, BoundParams);
return StructType;
}
llvm::DICompositeType *
createOpaqueStruct(llvm::DIScope *Scope, StringRef Name, llvm::DIFile *File,
unsigned Line, unsigned SizeInBits, unsigned AlignInBits,
llvm::DINode::DIFlags Flags, StringRef MangledName,
llvm::DINodeArray BoundParams = {},
llvm::DIType *SpecificationOf = nullptr) {
auto StructType = DBuilder.createStructType(
Scope, Name, File, Line, SizeInBits, AlignInBits, Flags,
/* DerivedFrom */ nullptr,
DBuilder.getOrCreateArray(ArrayRef<llvm::Metadata *>()),
llvm::dwarf::DW_LANG_Swift, nullptr, MangledName, SpecificationOf);
if (BoundParams)
DBuilder.replaceArrays(StructType, nullptr, BoundParams);
return StructType;
return createStruct(Scope, Name, File, Line, SizeInBits, AlignInBits, Flags,
MangledName, {}, BoundParams, SpecificationOf);
}
bool shouldCacheDIType(llvm::DIType *DITy, DebugTypeInfo &DbgTy) {
@@ -1794,7 +1826,20 @@ private:
llvm_unreachable("not a real type");
case TypeKind::BuiltinFixedArray: {
// TODO: provide proper array debug info
if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) {
auto *FixedArray = llvm::cast<swift::BuiltinFixedArrayType>(BaseTy);
llvm::DIType *ElementTy = getOrCreateType(FixedArray->getElementType());
llvm::SmallVector<llvm::Metadata *, 2> Subscripts;
if (auto NumElts = FixedArray->getFixedInhabitedSize()) {
auto *NumEltsNode = llvm::ConstantAsMetadata::get(
llvm::ConstantInt::get(IGM.Int64Ty, *NumElts));
Subscripts.push_back(DBuilder.getOrCreateSubrange(
NumEltsNode /*count*/, nullptr /*lowerBound*/,
nullptr /*upperBound*/, nullptr /*stride*/));
}
return DBuilder.createArrayType(SizeInBits, AlignInBits, ElementTy,
DBuilder.getOrCreateArray(Subscripts));
}
unsigned FwdDeclLine = 0;
return createOpaqueStruct(Scope, "Builtin.FixedArray", MainFile,
FwdDeclLine, SizeInBits, AlignInBits, Flags,
@@ -1876,9 +1921,8 @@ private:
return createSpecializedStructOrClassType(
StructTy, Scope, L.File, L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
return createStructType(DbgTy, Decl, Scope, L.File, L.Line,
SizeInBits, AlignInBits, Flags, nullptr,
llvm::dwarf::DW_LANG_Swift, MangledName);
return createStructType(StructTy, Decl, Scope, L.File, L.Line,
SizeInBits, AlignInBits, Flags, MangledName);
}
StringRef Name = Decl->getName().str();
if (!SizeInBitsOrNull)
@@ -1910,9 +1954,9 @@ private:
ClassTy, Scope, L.File, L.Line, SizeInBits, AlignInBits,
Flags, MangledName);
auto *DIType = createStructType(
DbgTy, Decl, Scope, File, L.Line, SizeInBits, AlignInBits,
Flags, nullptr, llvm::dwarf::DW_LANG_Swift, MangledName);
auto *DIType =
createStructType(ClassTy, Decl, Scope, File, L.Line, SizeInBits,
AlignInBits, Flags, MangledName);
assert(DIType && "Unexpected null DIType!");
assert(DIType && "createStructType should never return null!");
auto SuperClassTy = ClassTy->getSuperclass();
@@ -2276,7 +2320,8 @@ private:
if (!isa<llvm::DICompositeType>(CachedType))
return true;
bool IsUnsubstituted =
getUnsubstituedType(DbgTy.getType(), getMangledName(DbgTy)).first;
getUnsubstituedType(DbgTy.getType(), getMangledName(DbgTy).Canonical)
.first;
std::optional<uint64_t> SizeInBits;
if (!IsUnsubstituted)
if (auto CompletedDbgTy = completeType(DbgTy))
@@ -2419,40 +2464,13 @@ private:
OriginallyDefinedInTypes.insert(MangledName);
}
llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy,
llvm::DIScope *Scope = nullptr) {
// Is this an empty type?
if (DbgTy.isNull())
// We can't use the empty type as an index into DenseMap.
return createType(DbgTy, "", TheCU, MainFile);
// Look in the cache first.
if (auto *DITy = getTypeOrNull(DbgTy.getType())) {
assert(sanityCheckCachedType(DbgTy, DITy));
return DITy;
}
// Second line of defense: Look up the mangled name. TypeBase*'s are
// not necessarily unique, but name mangling is too expensive to do
// every time.
StringRef MangledName;
llvm::MDString *UID = nullptr;
if (canMangle(DbgTy.getType())) {
MangledName = getMangledName(DbgTy);
UID = llvm::MDString::get(IGM.getLLVMContext(), MangledName);
if (llvm::Metadata *CachedTy = DIRefMap.lookup(UID)) {
auto DITy = cast<llvm::DIType>(CachedTy);
assert(sanityCheckCachedType(DbgTy, DITy));
return DITy;
}
}
// Retrieve the context of the type, as opposed to the DeclContext
// of the variable.
//
// FIXME: Builtin and qualified types in LLVM have no parent
// scope. TODO: This can be fixed by extending DIBuilder.
// Make sure to retrieve the context of the type alias, not the pointee.
/// Retrieve the context of the type, as opposed to the DeclContext
/// of the variable.
///
/// FIXME: Builtin and qualified types in LLVM have no parent
/// scope. TODO: This can be fixed by extending DIBuilder.
/// Make sure to retrieve the context of the type alias, not the pointee.
llvm::DIScope *updateScope(llvm::DIScope *Scope, DebugTypeInfo DbgTy) {
DeclContext *Context = nullptr;
const Decl *TypeDecl = nullptr;
const clang::Decl *ClangDecl = nullptr;
@@ -2504,13 +2522,71 @@ private:
// Scope outermost fileprivate decls in an inline private discriminator
// namespace.
StringRef Name = MangledName;
if (auto *Decl = DbgTy.getDecl()) {
Name = Decl->getName().str();
if (auto *Decl = DbgTy.getDecl())
if (Decl->isOutermostPrivateOrFilePrivateScope())
Scope = getFilePrivateScope(Scope, Decl);
return Scope;
}
llvm::DIType *getOrCreateType(DebugTypeInfo DbgTy,
llvm::DIScope *Scope = nullptr) {
// Is this an empty type?
if (DbgTy.isNull())
// We can't use the empty type as an index into DenseMap.
return createType(DbgTy, "", TheCU, MainFile);
// Look in the cache first.
if (auto *DITy = getTypeOrNull(DbgTy.getType())) {
assert(sanityCheckCachedType(DbgTy, DITy));
return DITy;
}
// Second line of defense: Look up the mangled name. TypeBase*'s are
// not necessarily unique, but name mangling is too expensive to do
// every time.
MangledNames Mangled;
llvm::MDString *UID = nullptr;
if (canMangle(DbgTy.getType())) {
Mangled = getMangledName(DbgTy);
if (!Mangled.Sugared.empty()) {
UID = llvm::MDString::get(IGM.getLLVMContext(), Mangled.Sugared);
if (llvm::Metadata *CachedTy = DIRefMap.lookup(UID))
return cast<llvm::DIType>(CachedTy);
if (DbgTy.getType()->getKind() != swift::TypeKind::TypeAlias) {
// A type with the same canonical type already exists, emit a typedef.
// This extra step is necessary to break out of loops: We don't
// canoncialize types before mangling to preserver sugared types. But
// some types can also have different equivalent non-canonical
// representations with no sugar involved, for example a type
// recursively that appears iniside itself. To deal with the latter we
// directly emit a type alias to the canonical type.
UID = llvm::MDString::get(IGM.getLLVMContext(), Mangled.Canonical);
if (llvm::Metadata *CachedTy = DIRefMap.lookup(UID)) {
Scope = updateScope(Scope, DbgTy);
llvm::DIType *DITy = cast<llvm::DIType>(CachedTy);
llvm::DIType *TypeDef = DBuilder.createTypedef(
DITy, Mangled.Sugared, MainFile, 0, Scope);
return TypeDef;
}
UID = llvm::MDString::get(IGM.getLLVMContext(), Mangled.Sugared);
}
// Fall through and create the sugared type.
} else if (llvm::Metadata *CachedTy = DIRefMap.lookup(UID)) {
auto *DITy = cast<llvm::DIType>(CachedTy);
assert(sanityCheckCachedType(DbgTy, DITy));
return DITy;
}
}
Scope = updateScope(Scope, DbgTy);
StringRef MangledName =
!Mangled.Sugared.empty() ? Mangled.Sugared : Mangled.Canonical;
StringRef Name = MangledName;
if (auto *Decl = DbgTy.getDecl())
Name = Decl->getName().str();
// If this is a forward decl, create one for this mangled name and don't
// cache it.
if (!isa<PrimaryArchetypeType>(DbgTy.getType()) &&

View File

@@ -12,19 +12,14 @@ public let s = S<Int>(t: 0)
// CHECK: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]])
// CHECK: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, {{.*}}identifier: "$sSiD"
// DWARF: !DICompositeType(tag: DW_TAG_structure_type,
// DWARF-SAME: templateParams: ![[PARAMS:[0-9]+]]
// DWARF-SAME: identifier: "$s18BoundGenericStruct1SVySiGD"
// DWARF-SAME: specification:
// DWARF-DAG: !DICompositeType(tag: DW_TAG_structure_type, {{.*}}templateParams: ![[PARAMS:[0-9]+]]{{.*}}identifier: "$s18BoundGenericStruct1SVySiGD"{{.*}}specification:
// DWARF: ![[PARAMS]] = !{![[INTPARAM:[0-9]+]]}
// DWARF: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]])
// DWARF: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Int", {{.*}}identifier: "$sSiD"
// DWARF-DAG: ![[PARAMS]] = !{![[INTPARAM:[0-9]+]]}
// DWARF-DAG: ![[INTPARAM]] = !DITemplateTypeParameter(type: ![[INT:[0-9]+]])
// DWARF-DAG: ![[INT]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Int", {{.*}}identifier: "$sSiD"
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "S",
// DWARF-SAME: identifier: "$s18BoundGenericStruct1SVyxGD")
// DWARF: !DIDerivedType(tag: DW_TAG_member, name: "t"
// DWARF: ![[GENERIC_PARAM_TYPE:[0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$sxD"
// DWARF-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "S", {{.*}}identifier: "$s18BoundGenericStruct1SVyxGD")
// DWARF-DAG: !DIDerivedType(tag: DW_TAG_member, name: "t"
public struct S2<T> {
@@ -39,17 +34,15 @@ public let inner = S2<Double>.Inner(t:4.2)
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
// CHECK-SAME: flags: DIFlagFwdDecl, runtimeLang: DW_LANG_Swift)
// DWARF: !DICompositeType(tag: DW_TAG_structure_type, name: "Inner", scope: ![[SCOPE1:[0-9]+]],{{.*}} size: 64, {{.*}}, templateParams: ![[PARAMS2:[0-9]+]], identifier: "$s18BoundGenericStruct2S2V5InnerVySd_GD",{{.*}} specification: ![[SPECIFICATION:[0-9]+]]
// DWARF: ![[SCOPE1]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
// DWARF-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "Inner", scope: ![[SCOPE1:[0-9]+]],{{.*}} size: 64, elements: ![[ELEMENTS1:[0-9]+]], {{.*}}templateParams: ![[PARAMS2:[0-9]+]], identifier: "$s18BoundGenericStruct2S2V5InnerVySd_GD", specification: ![[SPECIFICATION:[0-9]+]])
// DWARF-DAG: ![[SCOPE1]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$s18BoundGenericStruct2S2VyxGD",
// DWARF: ![[PARAMS2]] = !{![[PARAMS3:[0-9]+]]}
// DWARF: ![[PARAMS3]] = !DITemplateTypeParameter(type: ![[PARAMS4:[0-9]+]])
// DWARF: ![[PARAMS4]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Double",
// DWARF-SAME: size: 64, {{.*}}runtimeLang: DW_LANG_Swift, identifier: "$sSdD")
// DWARF-DAG: ![[PARAMS2]] = !{![[PARAMS3:[0-9]+]]}
// DWARF-DAG: ![[PARAMS3]] = !DITemplateTypeParameter(type: ![[PARAMS4:[0-9]+]])
// DWARF-DAG: ![[PARAMS4]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Double"{{.*}} size: 64, {{.*}}runtimeLang: DW_LANG_Swift,{{.*}} identifier: "$sSdD")
// DWARF: [[SPECIFICATION]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Inner",
// DWARF-SAME: elements: ![[ELEMENTS1:[0-9]+]], runtimeLang: DW_LANG_Swift, identifier: "$s18BoundGenericStruct2S2V5InnerVyx_GD")
// DWARF-DAG: [[SPECIFICATION]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Inner", {{.*}}runtimeLang: DW_LANG_Swift, identifier: "$s18BoundGenericStruct2S2V5InnerVyx_GD")
// DWARF: ![[ELEMENTS1]] = !{![[ELEMENTS2:[0-9]+]]}
// DWARF-DAG: ![[ELEMENTS1]] = !{![[ELEMENTS2:[0-9]+]]}
// DWARF: ![[ELEMENTS2]] = !DIDerivedType(tag: DW_TAG_member, name: "t", {{.*}}, baseType: ![[GENERIC_PARAM_TYPE]])
// DWARF-DAG: ![[ELEMENTS2]] = !DIDerivedType(tag: DW_TAG_member, name: "t"

View File

@@ -7,7 +7,7 @@ class SomeClass {
// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "SomeClass",
// CHECK-SAME: size: {{64|32}}, elements:
// CHECK-SAME: runtimeLang: DW_LANG_Swift, identifier: "$s7classes9SomeClassCD")
// CHECK-SAME: runtimeLang: DW_LANG_Swift,{{.*}} identifier: "$s7classes9SomeClassCD")
// CHECK: !DIDerivedType(tag: DW_TAG_member, name: "first",
// CHECK-SAME: size: {{64|32}})

View File

@@ -25,12 +25,12 @@ enum Either {
// DWARF: DIDerivedType(tag: DW_TAG_member, name: "Neither",
// DWARF-SAME: baseType: null)
}
// CHECK: ![[EMPTY:.*]] = !{}
let E : Either = .Neither;
// CHECK: !DICompositeType({{.*}}name: "Color",
// CHECK-SAME: size: 8,
// CHECK-SAME: identifier: "$s4enum5ColorOD"
enum Color : UInt64 {
// This is effectively a 2-bit bitfield:
// DWARF: DICompositeType(tag: DW_TAG_enumeration_type, name: "Color",
@@ -72,8 +72,7 @@ let movie : Maybe<Color> = .none
public enum Nothing { }
public func foo(_ empty : Nothing) { }
// CHECK: !DICompositeType({{.*}}name: "Nothing", {{.*}}elements: ![[EMPTY]]
// CHECK: !DICompositeType({{.*}}name: "Nothing"
// CHECK: !DICompositeType({{.*}}name: "$s4enum4RoseOyxG{{z?}}D"
enum Rose<A> {
case MkRose(() -> A, () -> [Rose<A>])

View File

@@ -19,7 +19,7 @@ public struct Generic<T : P> {
// But only one concrete type is expected.
// CHECK: !DISubprogram({{.*}}linkageName: "$s4main8ConcreteV3getSiSgyF",
// CHECK-SAME: scope: ![[CONC:[0-9]+]],
// CHECK: ![[CONC]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Concrete", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, elements: !{{[0-9]+}}, runtimeLang: DW_LANG_Swift, identifier: "$s4main8ConcreteVD")
// CHECK: ![[CONC]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Concrete", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, runtimeLang: DW_LANG_Swift, identifier: "$s4main8ConcreteVD")
public struct Concrete {
public func get() -> Int? {
return nil

View File

@@ -0,0 +1,55 @@
// RUN: %target-swift-frontend -primary-file %s -emit-ir -gdwarf-types -o - | %FileCheck %s
protocol TraitsProtocol {
associatedtype IntType: FixedWidthInteger
}
final class MyClass<SomeTraits: TraitsProtocol> {
typealias Traits = SomeTraits
private var blame: MyClass<Traits>?
}
struct Traits32: TraitsProtocol {
typealias IntType = UInt32
}
let v : MyClass<Traits32>? = nil
// This typedef is not necessary from a semantic point of view, but the result
// of a trade-off done to preserve type sugar (= not generally canonicalizing types).
// CHECK-DAG: !DIDerivedType(tag: DW_TAG_typedef, name: "$s4main7MyClassCyAC6TraitsayAA8Traits32V_GGSgD", {{.*}}baseType: ![[CANONICAL:[0-9]+]])
// CHECK-DAG: ![[CANONICAL]] = !DICompositeType(tag: DW_TAG_structure_type, {{.*}}identifier: "$s4main7MyClassCyAA8Traits32VGSgD", specification: ![[OPTIONAL:[0-9]+]])
// CHECK-DAG: ![[OPTIONAL]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Optional"
// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass", {{.*}}templateParams: ![[PARAMS:[0-9]+]], identifier: "$s4main7MyClassCyAA8Traits32VGD", specification: ![[SPEC:[0-9]+]])
// CHECK-DAG: ![[PARAMS]] = !{![[PARAM:[0-9]+]]}
// CHECK-DAG: ![[PARAM]] = !DITemplateTypeParameter(type: ![[TRAITS32:[0-9]+]])
// CHECK-DAG: ![[TRAITS32]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Traits32"
// CHECK-DAG: ![[SPEC]] = !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass", {{.*}}identifier: "$s4main7MyClassCyxGD")
// have a second cache from (DIScope???, CanonicalMangledName) -> DIType
// if is non-canonical type emit a typealias to DIType.
struct C {}
struct A {
typealias B = C
let b: B
}
struct D {
typealias B = C
let b: B
}
let a : A? = nil
let b : D? = nil
// Check that the mechanism creating the canoicalization typedefs, doesn't merge
// more than it should:
// CHECK-DAG: ![[B1:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$s4main1AV1BaD"
// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "b", {{.*}} baseType: ![[B1]])
// CHECK-DAG: ![[B2:[0-9]+]] = !DIDerivedType(tag: DW_TAG_typedef, name: "$s4main1DV1BaD"
// CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "b", {{.*}}, baseType: ![[B2]])

View File

@@ -127,3 +127,15 @@ extension Up where A.A == Int {
var gg: DependentAlias<Self> = 123
}
}
typealias UsedAsGenericParameter = Float
struct S<T> {}
public func bar() {
let s = S<UsedAsGenericParameter>()
// CHECK-DAG: !DILocalVariable(name: "s",{{.*}} type: ![[LET_S_WITH_ALIAS:[0-9]+]]
// CHECK-DAG: ![[LET_S_WITH_ALIAS]] = !DIDerivedType(tag: DW_TAG_const_type, baseType: ![[S_WITH_ALIAS:[0-9]+]]
// CHECK-DAG: ![[S_WITH_ALIAS]] = !DICompositeType(tag: DW_TAG_structure_type, {{.*}}elements: ![[ELTS:[0-9]+]]
// CHECK-DAG: ![[ELTS]] = !{![[MEMBER:[0-9]+]]}
// CHECK-DAG: ![[MEMBER]] = !DIDerivedType(tag: DW_TAG_member, {{.*}}baseType: ![[USED_AS_GENERIC:[0-9]+]])
// CHECK-DAG: ![[USED_AS_GENERIC]] = !DICompositeType(tag: DW_TAG_structure_type, name: "$s9typealias1SVyAA22UsedAsGenericParameteraGD"
}

View File

@@ -1,6 +1,14 @@
// RUN: %target-swift-frontend %s -emit-ir -parse-as-library -module-name a -g -o - | %FileCheck %s
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "$s1a10LocalAliasaD", {{.*}}baseType: ![[BASETY:[0-9]+]]
// CHECK: ![[BASETY]]{{.*}}$sSbD
// FIXME: While we can preserve that ClassAlias = MyClass<LocalAlias, Bool>
// and we can preserve that MyClass<LocalAlias, Bool> = MyClass<Bool, Bool>
// we cannot preserve that LocalAlias = Bool.
// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "$s1a7MyClassCyAA10LocalAliasaSbGD",{{.*}}baseType: ![[BOOLBOOLTY:[0-9]+]]
// CHECK: ![[BOOLBOOLTY]] = !DICompositeType(tag: DW_TAG_structure_type, name: "MyClass", {{.*}}identifier: "$s1a7MyClassCyS2bGD"
// FIXME: !DIDerivedType(tag: DW_TAG_typedef, name: "$s1a10LocalAliasaD", {{.*}}baseType: ![[BASETY:[0-9]+]]
// FIXME: ![[BASETY]]{{.*}}$sSbD
public class MyClass<A, B> {}
public typealias LocalAlias = Bool
public typealias ClassAlias = MyClass<LocalAlias, Bool>

View File

@@ -5,12 +5,19 @@
// REQUIRES: swift_feature_Embedded
// REQUIRES: swift_feature_ValueGenerics
// CHECK-DAG: !DICompositeType({{.*}}templateParams: ![[SLAB_PARAMS:.*]], {{.*}}identifier: "$es11InlineArrayVy$0_4main8MySpriteVGD"
// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "InlineArray",{{.*}}size: 64{{.*}}elements: ![[ELTS:[0-9]+]], runtimeLang: DW_LANG_Swift, templateParams: ![[SLAB_PARAMS:[0-9]+]], identifier: "$es11InlineArrayVy$0_4main8MySpriteVGD", specification:
// CHECK-DAG: ![[SLAB_PARAMS]] = !{![[COUNT_PARAM:.*]], ![[ELEMENT_PARAM:.*]]}
// CHECK-DAG: ![[COUNT_PARAM]] = !DITemplateTypeParameter(type: ![[COUNT_TYPE:.*]])
// CHECK-DAG: ![[COUNT_TYPE]] = !DICompositeType({{.*}}name: "$e$0_D"
// CHECK-DAG: ![[ELEMENT_PARAM]] = !DITemplateTypeParameter(type: ![[ELEMENT_TYPE:.*]])
// CHECK-DAG: ![[ELEMENT_TYPE]] = !DICompositeType({{.*}}name: "MySprite", {{.*}}identifier: "$e4main8MySpriteVD"
// CHECK-DAG: ![[ELTS]] = !{![[STORAGE_MEMBER:.*]]}
// CHECK-DAG: ![[STORAGE_MEMBER]] = !DIDerivedType(tag: DW_TAG_member, name: "_storage",{{.*}}baseType: ![[ARRAY:[0-9]+]], size: 64
// CHECK-DAG: ![[ARRAY]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[ELEMENT_TYPE]], size: 64, elements: ![[SUBRANGES:[0-9]+]])
// CHECK-DAG: ![[SUBRANGES]] = !{![[DIM:[0-9]+]]}
// CHECK-DAG: ![[DIM]] = !DISubrange(count: 1)
struct MySprites {
var bricks: InlineArray<1, MySprite>
}