|
| 1 | +diff --git a/include/clang/AST/CXXInheritance.h b/include/clang/AST/CXXInheritance.h |
| 2 | +index bbef01843e0b..4b5492124eff 100644 |
| 3 | +--- a/include/clang/AST/CXXInheritance.h |
| 4 | ++++ b/include/clang/AST/CXXInheritance.h |
| 5 | +@@ -28,6 +28,8 @@ |
| 6 | + #include <memory> |
| 7 | + #include <utility> |
| 8 | + |
| 9 | ++#include "clang/AST/ASTContext.h" |
| 10 | ++ |
| 11 | + namespace clang { |
| 12 | + |
| 13 | + class ASTContext; |
| 14 | +@@ -132,7 +134,8 @@ class CXXBasePaths { |
| 15 | + struct IsVirtBaseAndNumberNonVirtBases { |
| 16 | + LLVM_PREFERRED_TYPE(bool) |
| 17 | + unsigned IsVirtBase : 1; |
| 18 | +- unsigned NumberOfNonVirtBases : 31; |
| 19 | ++ unsigned HackedRecord : 1; |
| 20 | ++ unsigned NumberOfNonVirtBases : 30; |
| 21 | + }; |
| 22 | + llvm::SmallDenseMap<QualType, IsVirtBaseAndNumberNonVirtBases, 8> |
| 23 | + ClassSubobjects; |
| 24 | +@@ -163,6 +166,28 @@ class CXXBasePaths { |
| 25 | + /// is also recorded. |
| 26 | + bool DetectVirtual; |
| 27 | + |
| 28 | ++ |
| 29 | ++ |
| 30 | ++ std::vector<clang::CXXBaseSpecifier *> _candidates; |
| 31 | ++ void addCandidate(ASTContext &Context, const CXXRecordDecl* candi) { |
| 32 | ++ clang::QualType baseType = candi->getTypeForDecl()->getCanonicalTypeInternal(); |
| 33 | ++ clang::SourceLocation loc = candi->getLocation(); |
| 34 | ++ clang::SourceRange R = candi->getSourceRange(); |
| 35 | ++ |
| 36 | ++ clang::TypeSourceInfo *typeSourceInfo = Context.getTrivialTypeSourceInfo(baseType); |
| 37 | ++ |
| 38 | ++ auto ptr = new clang::CXXBaseSpecifier( |
| 39 | ++ R, |
| 40 | ++ false,/* isVirtual */ |
| 41 | ++ true, |
| 42 | ++ clang::AS_public, |
| 43 | ++ typeSourceInfo, |
| 44 | ++ loc |
| 45 | ++ ); |
| 46 | ++ |
| 47 | ++ _candidates.push_back(ptr); |
| 48 | ++ } |
| 49 | ++ |
| 50 | + bool lookupInBases(ASTContext &Context, const CXXRecordDecl *Record, |
| 51 | + CXXRecordDecl::BaseMatchesCallback BaseMatches, |
| 52 | + bool LookupInDependent = false); |
| 53 | +diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp |
| 54 | +index 25de2a20a7f3..bd6e622707b5 100644 |
| 55 | +--- a/lib/AST/CXXInheritance.cpp |
| 56 | ++++ b/lib/AST/CXXInheritance.cpp |
| 57 | +@@ -39,7 +39,7 @@ using namespace clang; |
| 58 | + bool CXXBasePaths::isAmbiguous(CanQualType BaseType) { |
| 59 | + BaseType = BaseType.getUnqualifiedType(); |
| 60 | + IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects[BaseType]; |
| 61 | +- return Subobjects.NumberOfNonVirtBases + (Subobjects.IsVirtBase ? 1 : 0) > 1; |
| 62 | ++ return (Subobjects.NumberOfNonVirtBases + (Subobjects.IsVirtBase ? 1 : 0)) * (1-Subobjects.HackedRecord) > 1; |
| 63 | + } |
| 64 | + |
| 65 | + /// clear - Clear out all prior path information. |
| 66 | +@@ -70,12 +70,65 @@ bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const { |
| 67 | + return isDerivedFrom(Base, Paths); |
| 68 | + } |
| 69 | + |
| 70 | ++static bool isTString(const CXXRecordDecl *decl) { |
| 71 | ++ if (decl->getName() != "TBasicString") return false; |
| 72 | ++ |
| 73 | ++ auto* me = cast_or_null<const ClassTemplateSpecializationDecl>(decl); |
| 74 | ++ if (!me) return false; |
| 75 | ++ |
| 76 | ++ auto& templArgs = me->getTemplateInstantiationArgs(); |
| 77 | ++ if (templArgs.size() != 2) return false; |
| 78 | ++ |
| 79 | ++ if (templArgs[0].getKind() != clang::TemplateArgument::ArgKind::Type) return false; |
| 80 | ++ |
| 81 | ++ return true; /* need check that first template arg is char */ |
| 82 | ++} |
| 83 | ++ |
| 84 | ++static bool isXString(const CXXRecordDecl *decl) { |
| 85 | ++ return decl->getName() == "XString"; |
| 86 | ++} |
| 87 | ++ |
| 88 | ++// Function to compare template specialization types |
| 89 | ++bool AreCXXRecordDeclTemplatesEqual(const CXXRecordDecl *lhsDecl, const CXXRecordDecl *rhsDecl) { |
| 90 | ++ if (!lhsDecl || !rhsDecl) return lhsDecl == rhsDecl; |
| 91 | ++ auto* lhsTemplate = cast_or_null<const ClassTemplateSpecializationDecl>(lhsDecl); |
| 92 | ++ auto* rhsTemplate = cast_or_null<const ClassTemplateSpecializationDecl>(rhsDecl); |
| 93 | ++ if (!lhsTemplate || !rhsTemplate) return lhsTemplate == rhsTemplate; |
| 94 | ++ |
| 95 | ++ auto fromTy = QualType(lhsDecl->getTypeForDecl(), 0).getAsString(); |
| 96 | ++ auto toTy = QualType(rhsDecl->getTypeForDecl(), 0).getAsString(); |
| 97 | ++ |
| 98 | ++ auto isSpace = [](int ch) { return ch == ' '; }; |
| 99 | ++ llvm::erase_if(fromTy, isSpace); |
| 100 | ++ llvm::erase_if(toTy, isSpace); |
| 101 | ++ |
| 102 | ++ auto rm = [](std::string& str, const std::string& toRemove) { |
| 103 | ++ size_t pos = 0; |
| 104 | ++ while ((pos = str.find(toRemove, pos)) != std::string::npos) { |
| 105 | ++ str.erase(pos, toRemove.length()); |
| 106 | ++ } |
| 107 | ++ }; |
| 108 | ++ std::string reps[] = { |
| 109 | ++ "structTBasicString<char>", "structXString", |
| 110 | ++ "classTBasicString<char>", "classXString" |
| 111 | ++ }; |
| 112 | ++ for (const std::string& rep : reps) { |
| 113 | ++ rm(fromTy, rep); |
| 114 | ++ rm(toTy, rep); |
| 115 | ++ } |
| 116 | ++ |
| 117 | ++ return fromTy == toTy; |
| 118 | ++} |
| 119 | + bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, |
| 120 | + CXXBasePaths &Paths) const { |
| 121 | + if (getCanonicalDecl() == Base->getCanonicalDecl()) |
| 122 | + return false; |
| 123 | + |
| 124 | +- Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); |
| 125 | ++ bool r = isTString(this) && isXString(Base); |
| 126 | ++ if (r || AreCXXRecordDeclTemplatesEqual(this, Base)) { |
| 127 | ++ const CXXRecordDecl* xstring = Base->getCanonicalDecl(); |
| 128 | ++ Paths.addCandidate(getASTContext(), xstring); |
| 129 | ++ } |
| 130 | + |
| 131 | + const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl(); |
| 132 | + return lookupInBases( |
| 133 | +@@ -165,7 +218,13 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, |
| 134 | + AccessSpecifier AccessToHere = ScratchPath.Access; |
| 135 | + bool IsFirstStep = ScratchPath.empty(); |
| 136 | + |
| 137 | +- for (const auto &BaseSpec : Record->bases()) { |
| 138 | ++ std::vector<const CXXBaseSpecifier*> _bases; |
| 139 | ++ for (const auto &BaseSpec : Record->bases()) _bases.push_back(&BaseSpec); |
| 140 | ++ if(!_candidates.empty()) _bases.push_back(_candidates.front()); |
| 141 | ++ |
| 142 | ++ for (const auto &BaseSpec_ptr : _bases) { |
| 143 | ++ bool HackedBase = _candidates.size() > 0 && _candidates.front() == BaseSpec_ptr; // our candidate |
| 144 | ++ const auto &BaseSpec = *BaseSpec_ptr; |
| 145 | + // Find the record of the base class subobjects for this type. |
| 146 | + QualType BaseType = |
| 147 | + Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType(); |
| 148 | +@@ -182,6 +241,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, |
| 149 | + // Determine whether we need to visit this base class at all, |
| 150 | + // updating the count of subobjects appropriately. |
| 151 | + IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType]; |
| 152 | ++ Subobjects.HackedRecord = (int)HackedBase; |
| 153 | + bool VisitBase = true; |
| 154 | + bool SetVirtual = false; |
| 155 | + if (BaseSpec.isVirtual()) { |
0 commit comments