|
25 | 25 | #include "clang/AST/DeclTemplate.h" |
26 | 26 | #include "clang/AST/Expr.h" |
27 | 27 | #include "clang/AST/RecordLayout.h" |
| 28 | +#include "clang/AST/RecursiveASTVisitor.h" |
28 | 29 | #include "clang/Basic/CodeGenOptions.h" |
29 | 30 | #include "clang/Basic/FileManager.h" |
30 | 31 | #include "clang/Basic/SourceManager.h" |
@@ -4855,11 +4856,173 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( |
4855 | 4856 | return GVE; |
4856 | 4857 | } |
4857 | 4858 |
|
| 4859 | +namespace { |
| 4860 | +struct ReconstitutableType : public RecursiveASTVisitor<ReconstitutableType> { |
| 4861 | + bool Reconstitutable = true; |
| 4862 | + bool VisitVectorType(VectorType *FT) { |
| 4863 | + Reconstitutable = false; |
| 4864 | + return false; |
| 4865 | + } |
| 4866 | + bool VisitAtomicType(AtomicType *FT) { |
| 4867 | + Reconstitutable = false; |
| 4868 | + return false; |
| 4869 | + } |
| 4870 | + bool TraverseEnumType(EnumType *ET) { |
| 4871 | + // Unnamed enums can't be reconstituted due to a lack of column info we |
| 4872 | + // produce in the DWARF, so we can't get Clang's full name back. |
| 4873 | + if (const auto *ED = dyn_cast<EnumDecl>(ET->getDecl())) { |
| 4874 | + if (!ED->getIdentifier()) { |
| 4875 | + Reconstitutable = false; |
| 4876 | + return false; |
| 4877 | + } |
| 4878 | + } |
| 4879 | + return true; |
| 4880 | + } |
| 4881 | + bool VisitFunctionProtoType(FunctionProtoType *FT) { |
| 4882 | + // noexcept is not encoded in DWARF, so the reversi |
| 4883 | + Reconstitutable &= !isNoexceptExceptionSpec(FT->getExceptionSpecType()); |
| 4884 | + return !Reconstitutable; |
| 4885 | + } |
| 4886 | + bool TraverseRecordType(RecordType *RT) { |
| 4887 | + // Unnamed classes/lambdas can't be reconstituted due to a lack of column |
| 4888 | + // info we produce in the DWARF, so we can't get Clang's full name back. |
| 4889 | + // But so long as it's not one of those, it doesn't matter if some sub-type |
| 4890 | + // of the record (a template parameter) can't be reconstituted - because the |
| 4891 | + // un-reconstitutable type itself will carry its own name. |
| 4892 | + const auto *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()); |
| 4893 | + if (!RD) |
| 4894 | + return true; |
| 4895 | + if (RD->isLambda() || !RD->getIdentifier()) { |
| 4896 | + Reconstitutable = false; |
| 4897 | + return false; |
| 4898 | + } |
| 4899 | + return true; |
| 4900 | + } |
| 4901 | +}; |
| 4902 | +} // anonymous namespace |
| 4903 | + |
| 4904 | +// Test whether a type name could be rebuilt from emitted debug info. |
| 4905 | +static bool IsReconstitutableType(QualType QT) { |
| 4906 | + ReconstitutableType T; |
| 4907 | + T.TraverseType(QT); |
| 4908 | + return T.Reconstitutable; |
| 4909 | +} |
| 4910 | + |
4858 | 4911 | std::string CGDebugInfo::GetName(const Decl *D, bool Qualified) const { |
4859 | 4912 | std::string Name; |
4860 | 4913 | llvm::raw_string_ostream OS(Name); |
4861 | | - if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) |
4862 | | - ND->getNameForDiagnostic(OS, getPrintingPolicy(), Qualified); |
| 4914 | + const NamedDecl *ND = dyn_cast<NamedDecl>(D); |
| 4915 | + if (!ND) |
| 4916 | + return Name; |
| 4917 | + codegenoptions::DebugTemplateNamesKind TemplateNamesKind = |
| 4918 | + CGM.getCodeGenOpts().getDebugSimpleTemplateNames(); |
| 4919 | + Optional<TemplateArgs> Args; |
| 4920 | + |
| 4921 | + bool IsOperatorOverload = false; // isa<CXXConversionDecl>(ND); |
| 4922 | + if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) { |
| 4923 | + Args = GetTemplateArgs(RD); |
| 4924 | + } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) { |
| 4925 | + Args = GetTemplateArgs(FD); |
| 4926 | + auto NameKind = ND->getDeclName().getNameKind(); |
| 4927 | + IsOperatorOverload |= |
| 4928 | + NameKind == DeclarationName::CXXOperatorName || |
| 4929 | + NameKind == DeclarationName::CXXConversionFunctionName; |
| 4930 | + } else if (auto *VD = dyn_cast<VarDecl>(ND)) { |
| 4931 | + Args = GetTemplateArgs(VD); |
| 4932 | + } |
| 4933 | + std::function<bool(ArrayRef<TemplateArgument>)> HasReconstitutableArgs = |
| 4934 | + [&](ArrayRef<TemplateArgument> Args) { |
| 4935 | + return llvm::all_of(Args, [&](const TemplateArgument &TA) { |
| 4936 | + switch (TA.getKind()) { |
| 4937 | + case TemplateArgument::Template: |
| 4938 | + // Easy to reconstitute - the value of the parameter in the debug |
| 4939 | + // info is the string name of the template. (so the template name |
| 4940 | + // itself won't benefit from any name rebuilding, but that's a |
| 4941 | + // representational limitation - maybe DWARF could be |
| 4942 | + // changed/improved to use some more structural representation) |
| 4943 | + return true; |
| 4944 | + case TemplateArgument::Declaration: |
| 4945 | + // Reference and pointer non-type template parameters point to |
| 4946 | + // variables, functions, etc and their value is, at best (for |
| 4947 | + // variables) represented as an address - not a reference to the |
| 4948 | + // DWARF describing the variable/function/etc. This makes it hard, |
| 4949 | + // possibly impossible to rebuild the original name - looking up the |
| 4950 | + // address in the executable file's symbol table would be needed. |
| 4951 | + return false; |
| 4952 | + case TemplateArgument::NullPtr: |
| 4953 | + // These could be rebuilt, but figured they're close enough to the |
| 4954 | + // declaration case, and not worth rebuilding. |
| 4955 | + return false; |
| 4956 | + case TemplateArgument::Pack: |
| 4957 | + // A pack is invalid if any of the elements of the pack are invalid. |
| 4958 | + return HasReconstitutableArgs(TA.getPackAsArray()); |
| 4959 | + case TemplateArgument::Integral: |
| 4960 | + // Larger integers get encoded as DWARF blocks which are a bit |
| 4961 | + // harder to parse back into a large integer, etc - so punting on |
| 4962 | + // this for now. Re-parsing the integers back into APInt is probably |
| 4963 | + // feasible some day. |
| 4964 | + return TA.getAsIntegral().getBitWidth() <= 64; |
| 4965 | + case TemplateArgument::Type: |
| 4966 | + return IsReconstitutableType(TA.getAsType()); |
| 4967 | + default: |
| 4968 | + llvm_unreachable("Other, unresolved, template arguments should " |
| 4969 | + "not be seen here"); |
| 4970 | + } |
| 4971 | + }); |
| 4972 | + }; |
| 4973 | + // A conversion operator presents complications/ambiguity if there's a |
| 4974 | + // conversion to class template that is itself a template, eg: |
| 4975 | + // template<typename T> |
| 4976 | + // operator ns::t1<T, int>(); |
| 4977 | + // This should be named, eg: "operator ns::t1<float, int><float>" |
| 4978 | + // (ignoring clang bug that means this is currently "operator t1<float>") |
| 4979 | + // but if the arguments were stripped, the consumer couldn't differentiate |
| 4980 | + // whether the template argument list for the conversion type was the |
| 4981 | + // function's argument list (& no reconstitution was needed) or not. |
| 4982 | + // This could be handled if reconstitutable names had a separate attribute |
| 4983 | + // annotating them as such - this would remove the ambiguity. |
| 4984 | + // |
| 4985 | + // Alternatively the template argument list could be parsed enough to check |
| 4986 | + // whether there's one list or two, then compare that with the DWARF |
| 4987 | + // description of the return type and the template argument lists to determine |
| 4988 | + // how many lists there should be and if one is missing it could be assumed(?) |
| 4989 | + // to be the function's template argument list & then be rebuilt. |
| 4990 | + // |
| 4991 | + // Other operator overloads that aren't conversion operators could be |
| 4992 | + // reconstituted but would require a bit more nuance about detecting the |
| 4993 | + // difference between these different operators during that rebuilding. |
| 4994 | + bool Reconstitutable = |
| 4995 | + Args && HasReconstitutableArgs(Args->Args) && !IsOperatorOverload; |
| 4996 | + |
| 4997 | + PrintingPolicy PP = getPrintingPolicy(); |
| 4998 | + |
| 4999 | + if (TemplateNamesKind == codegenoptions::DebugTemplateNamesKind::Full || |
| 5000 | + !Reconstitutable) { |
| 5001 | + ND->getNameForDiagnostic(OS, PP, Qualified); |
| 5002 | + } else { |
| 5003 | + bool Mangled = |
| 5004 | + TemplateNamesKind == codegenoptions::DebugTemplateNamesKind::Mangled; |
| 5005 | + // check if it's a template |
| 5006 | + if (Mangled) |
| 5007 | + OS << "_STN"; |
| 5008 | + |
| 5009 | + OS << ND->getDeclName(); |
| 5010 | + std::string EncodedOriginalName; |
| 5011 | + llvm::raw_string_ostream EncodedOriginalNameOS(EncodedOriginalName); |
| 5012 | + EncodedOriginalNameOS << ND->getDeclName(); |
| 5013 | + |
| 5014 | + if (Mangled) { |
| 5015 | + OS << "|"; |
| 5016 | + printTemplateArgumentList(OS, Args->Args, PP); |
| 5017 | + printTemplateArgumentList(EncodedOriginalNameOS, Args->Args, PP); |
| 5018 | +#ifndef NDEBUG |
| 5019 | + std::string CanonicalOriginalName; |
| 5020 | + llvm::raw_string_ostream OriginalOS(CanonicalOriginalName); |
| 5021 | + ND->getNameForDiagnostic(OriginalOS, PP, Qualified); |
| 5022 | + assert(EncodedOriginalNameOS.str() == OriginalOS.str()); |
| 5023 | +#endif |
| 5024 | + } |
| 5025 | + } |
4863 | 5026 | return Name; |
4864 | 5027 | } |
4865 | 5028 |
|
|
0 commit comments