std::vector<const NamedDecl *> CXXRecordDecl::lookupDependentName( const DeclarationName &Name, llvm::function_ref<bool(const NamedDecl *ND)> Filter) { std::vector<const NamedDecl *> Results; // Lookup in the class. DeclContext::lookup_result DirectResult = lookup(Name); if (!DirectResult.empty()) { for (const NamedDecl *ND : DirectResult) { if (Filter(ND)) Results.push_back(ND); } return Results; } // Perform lookup into our base classes. CXXBasePaths Paths; Paths.setOrigin(this); if (!lookupInBases( [&](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { return CXXRecordDecl::FindOrdinaryMemberInDependentClasses( Specifier, Path, Name); }, Paths, /*LookupInDependent=*/true)) return Results; for (const NamedDecl *ND : Paths.front().Decls) { if (Filter(ND)) Results.push_back(ND); } return Results; }
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches, CXXBasePaths &Paths, bool LookupInDependent) const { // If we didn't find anything, report that. if (!Paths.lookupInBases(getASTContext(), this, BaseMatches, LookupInDependent)) return false; // If we're not recording paths or we won't ever find ambiguities, // we're done. if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities()) return true; // C++ [class.member.lookup]p6: // When virtual base classes are used, a hidden declaration can be // reached along a path through the sub-object lattice that does // not pass through the hiding declaration. This is not an // ambiguity. The identical use with nonvirtual base classes is an // ambiguity; in that case there is no unique instance of the name // that hides all the others. // // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy // way to make it any faster. Paths.Paths.remove_if([&Paths](const CXXBasePath &Path) { for (const CXXBasePathElement &PE : Path) { if (!PE.Base->isVirtual()) continue; CXXRecordDecl *VBase = nullptr; if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>()) VBase = cast<CXXRecordDecl>(Record->getDecl()); if (!VBase) break; // The declaration(s) we found along this path were found in a // subobject of a virtual base. Check whether this virtual // base is a subobject of any other path; if so, then the // declaration in this path are hidden by that patch. for (const CXXBasePath &HidingP : Paths) { CXXRecordDecl *HidingClass = nullptr; if (const RecordType *Record = HidingP.back().Base->getType()->getAs<RecordType>()) HidingClass = cast<CXXRecordDecl>(Record->getDecl()); if (!HidingClass) break; if (HidingClass->isVirtuallyDerivedFrom(VBase)) return true; } } return false; }); return true; }
static uint64_t ComputeNonVirtualBaseClassOffset(ASTContext &Context, CXXBasePaths &Paths, unsigned Start) { uint64_t Offset = 0; const CXXBasePath &Path = Paths.front(); for (unsigned i = Start, e = Path.size(); i != e; ++i) { const CXXBasePathElement& Element = Path[i]; // Get the layout. const ASTRecordLayout &Layout = Context.getASTRecordLayout(Element.Class); const CXXBaseSpecifier *BS = Element.Base; // FIXME: enable test3 from virt.cc to not abort. if (BS->isVirtual()) return 0; assert(!BS->isVirtual() && "Should not see virtual bases here!"); const CXXRecordDecl *Base = cast<CXXRecordDecl>(BS->getType()->getAs<RecordType>()->getDecl()); // Add the offset. Offset += Layout.getBaseClassOffset(Base) / 8; } return Offset; }
bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); }
bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl(); // FIXME: Capturing 'this' is a workaround for name lookup bugs in GCC 4.7. return lookupInBases( [this, BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) { return FindBaseClass(Specifier, Path, BaseDecl); }, Paths); }
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, CXXBasePaths &Paths) const { // If we didn't find anything, report that. if (!Paths.lookupInBases(getASTContext(), this, BaseMatches, UserData)) return false; // If we're not recording paths or we won't ever find ambiguities, // we're done. if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities()) return true; // C++ [class.member.lookup]p6: // When virtual base classes are used, a hidden declaration can be // reached along a path through the sub-object lattice that does // not pass through the hiding declaration. This is not an // ambiguity. The identical use with nonvirtual base classes is an // ambiguity; in that case there is no unique instance of the name // that hides all the others. // // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy // way to make it any faster. for (CXXBasePaths::paths_iterator P = Paths.begin(), PEnd = Paths.end(); P != PEnd; /* increment in loop */) { bool Hidden = false; for (CXXBasePath::iterator PE = P->begin(), PEEnd = P->end(); PE != PEEnd && !Hidden; ++PE) { if (PE->Base->isVirtual()) { CXXRecordDecl *VBase = 0; if (const RecordType *Record = PE->Base->getType()->getAs<RecordType>()) VBase = cast<CXXRecordDecl>(Record->getDecl()); if (!VBase) break; // The declaration(s) we found along this path were found in a // subobject of a virtual base. Check whether this virtual // base is a subobject of any other path; if so, then the // declaration in this path are hidden by that patch. for (CXXBasePaths::paths_iterator HidingP = Paths.begin(), HidingPEnd = Paths.end(); HidingP != HidingPEnd; ++HidingP) { CXXRecordDecl *HidingClass = 0; if (const RecordType *Record = HidingP->back().Base->getType()->getAs<RecordType>()) HidingClass = cast<CXXRecordDecl>(Record->getDecl()); if (!HidingClass) break; if (HidingClass->isVirtuallyDerivedFrom(VBase)) { Hidden = true; break; } } } } if (Hidden) P = Paths.Paths.erase(P); else ++P; } return true; }
bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, void *UserData, CXXBasePaths &Paths) const { bool FoundPath = false; ASTContext &Context = getASTContext(); for (base_class_const_iterator BaseSpec = bases_begin(), BaseSpecEnd = bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) { // Find the record of the base class subobjects for this type. QualType BaseType = Context.getCanonicalType(BaseSpec->getType()) .getUnqualifiedType(); // C++ [temp.dep]p3: // In the definition of a class template or a member of a class template, // if a base class of the class template depends on a template-parameter, // the base class scope is not examined during unqualified name lookup // either at the point of definition of the class template or member or // during an instantiation of the class tem- plate or member. if (BaseType->isDependentType()) continue; // Determine whether we need to visit this base class at all, // updating the count of subobjects appropriately. std::pair<bool, unsigned>& Subobjects = Paths.ClassSubobjects[BaseType]; bool VisitBase = true; bool SetVirtual = false; if (BaseSpec->isVirtual()) { VisitBase = !Subobjects.first; Subobjects.first = true; if (Paths.isDetectingVirtual() && Paths.DetectedVirtual == 0) { // If this is the first virtual we find, remember it. If it turns out // there is no base path here, we'll reset it later. Paths.DetectedVirtual = BaseType->getAs<RecordType>(); SetVirtual = true; } } else ++Subobjects.second; if (Paths.isRecordingPaths()) { // Add this base specifier to the current path. CXXBasePathElement Element; Element.Base = &*BaseSpec; Element.Class = this; if (BaseSpec->isVirtual()) Element.SubobjectNumber = 0; else Element.SubobjectNumber = Subobjects.second; Paths.ScratchPath.push_back(Element); } if (BaseMatches(BaseSpec, Paths.ScratchPath, UserData)) { // We've found a path that terminates that this base. FoundPath = true; if (Paths.isRecordingPaths()) { // We have a path. Make a copy of it before moving on. Paths.Paths.push_back(Paths.ScratchPath); } else if (!Paths.isFindingAmbiguities()) { // We found a path and we don't care about ambiguities; // return immediately. return FoundPath; } } else if (VisitBase) { CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>() ->getDecl()); if (BaseRecord->lookupInBases(BaseMatches, UserData, Paths)) { // C++ [class.member.lookup]p2: // A member name f in one sub-object B hides a member name f in // a sub-object A if A is a base class sub-object of B. Any // declarations that are so hidden are eliminated from // consideration. // There is a path to a base class that meets the criteria. If we're // not collecting paths or finding ambiguities, we're done. FoundPath = true; if (!Paths.isFindingAmbiguities()) return FoundPath; } } // Pop this base specifier off the current path (if we're // collecting paths). if (Paths.isRecordingPaths()) Paths.ScratchPath.pop_back(); // If we set a virtual earlier, and this isn't a path, forget it again. if (SetVirtual && !FoundPath) { Paths.DetectedVirtual = 0; } } return FoundPath; }