mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[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:
@@ -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())
|
||||
|
||||
@@ -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()) &&
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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}})
|
||||
|
||||
@@ -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>])
|
||||
|
||||
@@ -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
|
||||
|
||||
55
test/DebugInfo/typealias-recursive.swift
Normal file
55
test/DebugInfo/typealias-recursive.swift
Normal 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]])
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user