diff --git a/lib/IRGen/DebugTypeInfo.cpp b/lib/IRGen/DebugTypeInfo.cpp index d0b3ed66afd11..e61788a989477 100644 --- a/lib/IRGen/DebugTypeInfo.cpp +++ b/lib/IRGen/DebugTypeInfo.cpp @@ -191,6 +191,8 @@ LLVM_DUMP_METHOD void DebugTypeInfo::dump() const { std::optional CompletedDebugTypeInfo::getFromTypeInfo(swift::Type Ty, const TypeInfo &Info, IRGenModule &IGM) { + if (!Ty || Ty->hasTypeParameter()) + return {}; auto *StorageType = IGM.getStorageTypeForUnlowered(Ty); std::optional SizeInBits; if (StorageType->isSized()) diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index ad9f907d38f6f..5e71b17010c91 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -458,11 +458,15 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { /// 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { !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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { !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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { } } - 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { return FwdDecl; } - llvm::DICompositeType * - createStructType(DebugTypeInfo DbgTy, NominalTypeDecl *Decl, Type BaseTy, - 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 Elements; unsigned OffsetInBits = 0; for (VarDecl *VD : Decl->getStoredProperties()) { - auto memberTy = BaseTy->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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { } } + // 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; } @@ -1712,23 +1735,32 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { } 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) { + 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, - DBuilder.getOrCreateArray(ArrayRef()), - llvm::dwarf::DW_LANG_Swift, nullptr, MangledName, SpecificationOf); + /* 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) { + return createStruct(Scope, Name, File, Line, SizeInBits, AlignInBits, Flags, + MangledName, {}, BoundParams, SpecificationOf); + } + bool shouldCacheDIType(llvm::DIType *DITy, DebugTypeInfo &DbgTy) { // Don't cache a type alias to a forward declaration either. if (DbgTy.isFixedBuffer() || DITy->isForwardDecl()) @@ -1794,7 +1826,20 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { llvm_unreachable("not a real type"); case TypeKind::BuiltinFixedArray: { - // TODO: provide proper array debug info + if (Opts.DebugInfoLevel > IRGenDebugInfoLevel::ASTTypes) { + auto *FixedArray = llvm::cast(BaseTy); + llvm::DIType *ElementTy = getOrCreateType(FixedArray->getElementType()); + llvm::SmallVector 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { return createSpecializedStructOrClassType( StructTy, Scope, L.File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); - return createStructType(DbgTy, Decl, StructTy, 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { ClassTy, Scope, L.File, L.Line, SizeInBits, AlignInBits, Flags, MangledName); - auto *DIType = createStructType( - DbgTy, Decl, ClassTy, 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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { if (!isa(CachedType)) return true; bool IsUnsubstituted = - getUnsubstituedType(DbgTy.getType(), getMangledName(DbgTy)).first; + getUnsubstituedType(DbgTy.getType(), getMangledName(DbgTy).Canonical) + .first; std::optional SizeInBits; if (!IsUnsubstituted) if (auto CompletedDbgTy = completeType(DbgTy)) @@ -2419,40 +2464,13 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { 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(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 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { // 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(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(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(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(DbgTy.getType()) && @@ -3326,6 +3402,9 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( if (!DInstLine || (ArgNo > 0 && VarInfo.Name == IGM.Context.Id_self.str())) Artificial = ArtificialValue; + if (VarInfo.Name == "index") + llvm::errs(); + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; if (Artificial || DITy->isArtificial() || DITy == InternalType) Flags |= llvm::DINode::FlagArtificial; @@ -3382,10 +3461,10 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( auto appendDIExpression = [&VarInfo, this](llvm::DIExpression *DIExpr, - llvm::DIExpression::FragmentInfo PieceFragment) - -> llvm::DIExpression * { + llvm::DIExpression::FragmentInfo PieceFragment, + bool IsFirstAndOnlyPiece) -> llvm::DIExpression * { if (!VarInfo.DIExpr) { - if (!PieceFragment.SizeInBits) + if (!PieceFragment.SizeInBits || IsFirstAndOnlyPiece) return DIExpr; return llvm::DIExpression::createFragmentExpression( @@ -3402,7 +3481,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( DIExpr = llvm::DIExpression::append(DIExpr, Operands); // Add the fragment of the SIL variable. - if (VarFragment.SizeInBits) + if (VarFragment.SizeInBits && !IsFirstAndOnlyPiece) DIExpr = llvm::DIExpression::createFragmentExpression( DIExpr, VarFragment.OffsetInBits, VarFragment.SizeInBits) .value_or(nullptr); @@ -3452,8 +3531,14 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( Fragment.OffsetInBits = OffsetInBits; Fragment.SizeInBits = SizeInBits; } + // LLVM complains if a single fragment covers the entire variable. This can + // happen if, e.g., the optimizer takes the _value out of an Int + // struct. Detect this case and don't emit a fragment. + bool IsFirstAndOnlyPiece = + !IsPiece && Fragment.OffsetInBits == 0 && + Fragment.SizeInBits == getSizeInBits(Var->getType()); llvm::DIExpression *DIExpr = DBuilder.createExpression(Operands); - DIExpr = appendDIExpression(DIExpr, Fragment); + DIExpr = appendDIExpression(DIExpr, Fragment, IsFirstAndOnlyPiece); if (DIExpr) emitDbgIntrinsic( Builder, Piece, Var, DIExpr, DInstLine, DInstLoc.Column, Scope, DS, @@ -3465,7 +3550,7 @@ void IRGenDebugInfoImpl::emitVariableDeclaration( if (Storage.empty()) { llvm::DIExpression::FragmentInfo NoFragment = {0, 0}; if (auto *DIExpr = - appendDIExpression(DBuilder.createExpression(), NoFragment)) + appendDIExpression(DBuilder.createExpression(), NoFragment, false)) emitDbgIntrinsic(Builder, llvm::ConstantInt::get(IGM.Int64Ty, 0), Var, DIExpr, DInstLine, DInstLoc.Column, Scope, DS, Indirection == CoroDirectValue || diff --git a/test/DebugInfo/BoundGenericStruct.swift b/test/DebugInfo/BoundGenericStruct.swift index 7401983b8a895..9c911b98a9751 100644 --- a/test/DebugInfo/BoundGenericStruct.swift +++ b/test/DebugInfo/BoundGenericStruct.swift @@ -12,19 +12,14 @@ public let s = S(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 { @@ -39,17 +34,15 @@ public let inner = S2.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" diff --git a/test/DebugInfo/classes.swift b/test/DebugInfo/classes.swift index 9e8924e9d8a34..6a9af93ff0d45 100644 --- a/test/DebugInfo/classes.swift +++ b/test/DebugInfo/classes.swift @@ -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}}) diff --git a/test/DebugInfo/enum.swift b/test/DebugInfo/enum.swift index e91611c2eba82..a8678ffabd142 100644 --- a/test/DebugInfo/enum.swift +++ b/test/DebugInfo/enum.swift @@ -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 = .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 { case MkRose(() -> A, () -> [Rose]) diff --git a/test/DebugInfo/parent-scope.swift b/test/DebugInfo/parent-scope.swift index 8ad42eb9a20ef..320faf4ea577f 100644 --- a/test/DebugInfo/parent-scope.swift +++ b/test/DebugInfo/parent-scope.swift @@ -19,7 +19,7 @@ public struct Generic { // 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 diff --git a/test/DebugInfo/typealias-recursive.swift b/test/DebugInfo/typealias-recursive.swift new file mode 100644 index 0000000000000..36ec728f29b97 --- /dev/null +++ b/test/DebugInfo/typealias-recursive.swift @@ -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 { + typealias Traits = SomeTraits + private var blame: MyClass? +} + +struct Traits32: TraitsProtocol { + typealias IntType = UInt32 +} + +let v : MyClass? = 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]]) diff --git a/test/DebugInfo/typealias.swift b/test/DebugInfo/typealias.swift index 23e2921a0210f..fde611c35b2ca 100644 --- a/test/DebugInfo/typealias.swift +++ b/test/DebugInfo/typealias.swift @@ -127,3 +127,15 @@ extension Up where A.A == Int { var gg: DependentAlias = 123 } } + +typealias UsedAsGenericParameter = Float +struct S {} +public func bar() { + let s = S() + // 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" +} diff --git a/test/DebugInfo/typealias_indirect.swift b/test/DebugInfo/typealias_indirect.swift index 9f04320a9fd20..005cbb386b5e9 100644 --- a/test/DebugInfo/typealias_indirect.swift +++ b/test/DebugInfo/typealias_indirect.swift @@ -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 +// and we can preserve that MyClass = MyClass +// 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 {} public typealias LocalAlias = Bool public typealias ClassAlias = MyClass diff --git a/test/DebugInfo/value-generics-embedded.swift b/test/DebugInfo/value-generics-embedded.swift index 5f0710df42a10..0acccf5576d2e 100644 --- a/test/DebugInfo/value-generics-embedded.swift +++ b/test/DebugInfo/value-generics-embedded.swift @@ -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> }