1//===- CXXInheritance.cpp - C++ Inheritance -------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file provides routines that help analyzing C++ inheritance hierarchies.
10//
11//===----------------------------------------------------------------------===//
12
13#include "clang/AST/CXXInheritance.h"
14#include "clang/AST/ASTContext.h"
15#include "clang/AST/Decl.h"
16#include "clang/AST/DeclBase.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/DeclTemplate.h"
19#include "clang/AST/RecordLayout.h"
20#include "clang/AST/TemplateName.h"
21#include "clang/AST/Type.h"
22#include "clang/Basic/LLVM.h"
23#include "llvm/ADT/DenseMap.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/ADT/iterator_range.h"
27#include <algorithm>
28#include <cassert>
29#include <utility>
30
31using namespace clang;
32
33/// isAmbiguous - Determines whether the set of paths provided is
34/// ambiguous, i.e., there are two or more paths that refer to
35/// different base class subobjects of the same type. BaseType must be
36/// an unqualified, canonical class type.
37bool CXXBasePaths::isAmbiguous(CanQualType BaseType) {
38 BaseType = BaseType.getUnqualifiedType();
39 IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects[BaseType];
40 return Subobjects.NumberOfNonVirtBases + (Subobjects.IsVirtBase ? 1 : 0) > 1;
41}
42
43/// clear - Clear out all prior path information.
44void CXXBasePaths::clear() {
45 Paths.clear();
46 ClassSubobjects.clear();
47 VisitedDependentRecords.clear();
48 ScratchPath.clear();
49 DetectedVirtual = nullptr;
50}
51
52/// Swaps the contents of this CXXBasePaths structure with the
53/// contents of Other.
54void CXXBasePaths::swap(CXXBasePaths &Other) {
55 std::swap(a&: Origin, b&: Other.Origin);
56 Paths.swap(x&: Other.Paths);
57 ClassSubobjects.swap(Other.ClassSubobjects);
58 VisitedDependentRecords.swap(RHS&: Other.VisitedDependentRecords);
59 std::swap(a&: FindAmbiguities, b&: Other.FindAmbiguities);
60 std::swap(a&: RecordPaths, b&: Other.RecordPaths);
61 std::swap(a&: DetectVirtual, b&: Other.DetectVirtual);
62 std::swap(a&: DetectedVirtual, b&: Other.DetectedVirtual);
63}
64
65bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const {
66 CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
67 /*DetectVirtual=*/false);
68 return isDerivedFrom(Base, Paths);
69}
70
71bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base,
72 CXXBasePaths &Paths) const {
73 if (getCanonicalDecl() == Base->getCanonicalDecl())
74 return false;
75
76 Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
77
78 const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl();
79 return lookupInBases(
80 BaseMatches: [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
81 return Specifier->getType()->getAsRecordDecl() &&
82 FindBaseClass(Specifier, Path, BaseRecord: BaseDecl);
83 },
84 Paths);
85}
86
87bool CXXRecordDecl::isVirtuallyDerivedFrom(const CXXRecordDecl *Base) const {
88 if (!getNumVBases())
89 return false;
90
91 CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false,
92 /*DetectVirtual=*/false);
93
94 if (getCanonicalDecl() == Base->getCanonicalDecl())
95 return false;
96
97 Paths.setOrigin(const_cast<CXXRecordDecl*>(this));
98
99 const CXXRecordDecl *BaseDecl = Base->getCanonicalDecl();
100 return lookupInBases(
101 BaseMatches: [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
102 return FindVirtualBaseClass(Specifier, Path, BaseRecord: BaseDecl);
103 },
104 Paths);
105}
106
107bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {
108 const CXXRecordDecl *TargetDecl = Base->getCanonicalDecl();
109 return forallBases(BaseMatches: [TargetDecl](const CXXRecordDecl *Base) {
110 return Base->getCanonicalDecl() != TargetDecl;
111 });
112}
113
114bool
115CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const {
116 assert(isDependentContext());
117
118 for (; !CurContext->isFileContext(); CurContext = CurContext->getParent())
119 if (CurContext->Equals(this))
120 return true;
121
122 return false;
123}
124
125bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches) const {
126 SmallVector<const CXXRecordDecl*, 8> Queue;
127
128 const CXXRecordDecl *Record = this;
129 while (true) {
130 for (const auto &I : Record->bases()) {
131 const RecordType *Ty = I.getType()->getAs<RecordType>();
132 if (!Ty)
133 return false;
134
135 CXXRecordDecl *Base =
136 cast_if_present<CXXRecordDecl>(Val: Ty->getDecl()->getDefinition());
137 if (!Base ||
138 (Base->isDependentContext() &&
139 !Base->isCurrentInstantiation(Record))) {
140 return false;
141 }
142
143 Queue.push_back(Elt: Base);
144 if (!BaseMatches(Base))
145 return false;
146 }
147
148 if (Queue.empty())
149 break;
150 Record = Queue.pop_back_val(); // not actually a queue.
151 }
152
153 return true;
154}
155
156bool CXXBasePaths::lookupInBases(ASTContext &Context,
157 const CXXRecordDecl *Record,
158 CXXRecordDecl::BaseMatchesCallback BaseMatches,
159 bool LookupInDependent) {
160 bool FoundPath = false;
161
162 // The access of the path down to this record.
163 AccessSpecifier AccessToHere = ScratchPath.Access;
164 bool IsFirstStep = ScratchPath.empty();
165
166 for (const auto &BaseSpec : Record->bases()) {
167 // Find the record of the base class subobjects for this type.
168 QualType BaseType =
169 Context.getCanonicalType(T: BaseSpec.getType()).getUnqualifiedType();
170
171 bool isCurrentInstantiation = isa<InjectedClassNameType>(Val: BaseType);
172 if (!isCurrentInstantiation) {
173 if (auto *BaseRecord = cast_if_present<CXXRecordDecl>(
174 Val: BaseSpec.getType()->getAsRecordDecl()))
175 isCurrentInstantiation = BaseRecord->isDependentContext() &&
176 BaseRecord->isCurrentInstantiation(Record);
177 }
178 // C++ [temp.dep]p3:
179 // In the definition of a class template or a member of a class template,
180 // if a base class of the class template depends on a template-parameter,
181 // the base class scope is not examined during unqualified name lookup
182 // either at the point of definition of the class template or member or
183 // during an instantiation of the class tem- plate or member.
184 if (!LookupInDependent &&
185 (BaseType->isDependentType() && !isCurrentInstantiation))
186 continue;
187
188 // Determine whether we need to visit this base class at all,
189 // updating the count of subobjects appropriately.
190 IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType];
191 bool VisitBase = true;
192 bool SetVirtual = false;
193 if (BaseSpec.isVirtual()) {
194 VisitBase = !Subobjects.IsVirtBase;
195 Subobjects.IsVirtBase = true;
196 if (isDetectingVirtual() && DetectedVirtual == nullptr) {
197 // If this is the first virtual we find, remember it. If it turns out
198 // there is no base path here, we'll reset it later.
199 DetectedVirtual = BaseType->getAs<RecordType>();
200 SetVirtual = true;
201 }
202 } else {
203 ++Subobjects.NumberOfNonVirtBases;
204 }
205 if (isRecordingPaths()) {
206 // Add this base specifier to the current path.
207 CXXBasePathElement Element;
208 Element.Base = &BaseSpec;
209 Element.Class = Record;
210 if (BaseSpec.isVirtual())
211 Element.SubobjectNumber = 0;
212 else
213 Element.SubobjectNumber = Subobjects.NumberOfNonVirtBases;
214 ScratchPath.push_back(Elt: Element);
215
216 // Calculate the "top-down" access to this base class.
217 // The spec actually describes this bottom-up, but top-down is
218 // equivalent because the definition works out as follows:
219 // 1. Write down the access along each step in the inheritance
220 // chain, followed by the access of the decl itself.
221 // For example, in
222 // class A { public: int foo; };
223 // class B : protected A {};
224 // class C : public B {};
225 // class D : private C {};
226 // we would write:
227 // private public protected public
228 // 2. If 'private' appears anywhere except far-left, access is denied.
229 // 3. Otherwise, overall access is determined by the most restrictive
230 // access in the sequence.
231 if (IsFirstStep)
232 ScratchPath.Access = BaseSpec.getAccessSpecifier();
233 else
234 ScratchPath.Access = CXXRecordDecl::MergeAccess(PathAccess: AccessToHere,
235 DeclAccess: BaseSpec.getAccessSpecifier());
236 }
237
238 // Track whether there's a path involving this specific base.
239 bool FoundPathThroughBase = false;
240
241 if (BaseMatches(&BaseSpec, ScratchPath)) {
242 // We've found a path that terminates at this base.
243 FoundPath = FoundPathThroughBase = true;
244 if (isRecordingPaths()) {
245 // We have a path. Make a copy of it before moving on.
246 Paths.push_back(x: ScratchPath);
247 } else if (!isFindingAmbiguities()) {
248 // We found a path and we don't care about ambiguities;
249 // return immediately.
250 return FoundPath;
251 }
252 } else if (VisitBase) {
253 CXXRecordDecl *BaseRecord = nullptr;
254 if (LookupInDependent) {
255 const TemplateSpecializationType *TST =
256 BaseSpec.getType()->getAs<TemplateSpecializationType>();
257 if (!TST) {
258 if (auto *RT = BaseSpec.getType()->getAs<RecordType>())
259 BaseRecord = cast<CXXRecordDecl>(Val: RT->getDecl());
260 } else {
261 TemplateName TN = TST->getTemplateName();
262 if (auto *TD =
263 dyn_cast_or_null<ClassTemplateDecl>(Val: TN.getAsTemplateDecl()))
264 BaseRecord = TD->getTemplatedDecl();
265 }
266 if (BaseRecord) {
267 if (!BaseRecord->hasDefinition())
268 BaseRecord = nullptr;
269 else if (!VisitedDependentRecords.insert(Ptr: BaseRecord).second)
270 BaseRecord = nullptr;
271 }
272 } else {
273 BaseRecord = cast<CXXRecordDecl>(Val: BaseSpec.getType()->getAsRecordDecl());
274 }
275 if (BaseRecord &&
276 lookupInBases(Context, Record: BaseRecord, BaseMatches, LookupInDependent)) {
277 // C++ [class.member.lookup]p2:
278 // A member name f in one sub-object B hides a member name f in
279 // a sub-object A if A is a base class sub-object of B. Any
280 // declarations that are so hidden are eliminated from
281 // consideration.
282
283 // There is a path to a base class that meets the criteria. If we're
284 // not collecting paths or finding ambiguities, we're done.
285 FoundPath = FoundPathThroughBase = true;
286 if (!isFindingAmbiguities())
287 return FoundPath;
288 }
289 }
290
291 // Pop this base specifier off the current path (if we're
292 // collecting paths).
293 if (isRecordingPaths()) {
294 ScratchPath.pop_back();
295 }
296
297 // If we set a virtual earlier, and this isn't a path, forget it again.
298 if (SetVirtual && !FoundPathThroughBase) {
299 DetectedVirtual = nullptr;
300 }
301 }
302
303 // Reset the scratch path access.
304 ScratchPath.Access = AccessToHere;
305
306 return FoundPath;
307}
308
309bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,
310 CXXBasePaths &Paths,
311 bool LookupInDependent) const {
312 // If we didn't find anything, report that.
313 if (!Paths.lookupInBases(Context&: getASTContext(), Record: this, BaseMatches,
314 LookupInDependent))
315 return false;
316
317 // If we're not recording paths or we won't ever find ambiguities,
318 // we're done.
319 if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities())
320 return true;
321
322 // C++ [class.member.lookup]p6:
323 // When virtual base classes are used, a hidden declaration can be
324 // reached along a path through the sub-object lattice that does
325 // not pass through the hiding declaration. This is not an
326 // ambiguity. The identical use with nonvirtual base classes is an
327 // ambiguity; in that case there is no unique instance of the name
328 // that hides all the others.
329 //
330 // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy
331 // way to make it any faster.
332 Paths.Paths.remove_if(pred: [&Paths](const CXXBasePath &Path) {
333 for (const CXXBasePathElement &PE : Path) {
334 if (!PE.Base->isVirtual())
335 continue;
336
337 CXXRecordDecl *VBase = nullptr;
338 if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>())
339 VBase = cast<CXXRecordDecl>(Val: Record->getDecl());
340 if (!VBase)
341 break;
342
343 // The declaration(s) we found along this path were found in a
344 // subobject of a virtual base. Check whether this virtual
345 // base is a subobject of any other path; if so, then the
346 // declaration in this path are hidden by that patch.
347 for (const CXXBasePath &HidingP : Paths) {
348 CXXRecordDecl *HidingClass = nullptr;
349 if (const RecordType *Record =
350 HidingP.back().Base->getType()->getAs<RecordType>())
351 HidingClass = cast<CXXRecordDecl>(Val: Record->getDecl());
352 if (!HidingClass)
353 break;
354
355 if (HidingClass->isVirtuallyDerivedFrom(Base: VBase))
356 return true;
357 }
358 }
359 return false;
360 });
361
362 return true;
363}
364
365bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,
366 CXXBasePath &Path,
367 const CXXRecordDecl *BaseRecord) {
368 assert(BaseRecord->getCanonicalDecl() == BaseRecord &&
369 "User data for FindBaseClass is not canonical!");
370 return cast<CXXRecordDecl>(Val: Specifier->getType()->getAsRecordDecl())
371 ->getCanonicalDecl() == BaseRecord;
372}
373
374bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,
375 CXXBasePath &Path,
376 const CXXRecordDecl *BaseRecord) {
377 assert(BaseRecord->getCanonicalDecl() == BaseRecord &&
378 "User data for FindBaseClass is not canonical!");
379 return Specifier->isVirtual() &&
380 cast<CXXRecordDecl>(Val: Specifier->getType()->getAsRecordDecl())
381 ->getCanonicalDecl() == BaseRecord;
382}
383
384static bool isOrdinaryMember(const NamedDecl *ND) {
385 return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |
386 Decl::IDNS_Member);
387}
388
389static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,
390 DeclarationName Name) {
391 Path.Decls = RD->lookup(Name).begin();
392 for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)
393 if (isOrdinaryMember(ND: *I))
394 return true;
395
396 return false;
397}
398
399bool CXXRecordDecl::hasMemberName(DeclarationName Name) const {
400 CXXBasePath P;
401 if (findOrdinaryMember(RD: this, Path&: P, Name))
402 return true;
403
404 CXXBasePaths Paths(false, false, false);
405 return lookupInBases(
406 BaseMatches: [Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {
407 return findOrdinaryMember(RD: Specifier->getType()->getAsCXXRecordDecl(),
408 Path, Name);
409 },
410 Paths);
411}
412
413void OverridingMethods::add(unsigned OverriddenSubobject,
414 UniqueVirtualMethod Overriding) {
415 SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides
416 = Overrides[OverriddenSubobject];
417 if (!llvm::is_contained(Range&: SubobjectOverrides, Element: Overriding))
418 SubobjectOverrides.push_back(Elt: Overriding);
419}
420
421void OverridingMethods::add(const OverridingMethods &Other) {
422 for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) {
423 for (overriding_const_iterator M = I->second.begin(),
424 MEnd = I->second.end();
425 M != MEnd;
426 ++M)
427 add(OverriddenSubobject: I->first, Overriding: *M);
428 }
429}
430
431void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) {
432 for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) {
433 I->second.clear();
434 I->second.push_back(Elt: Overriding);
435 }
436}
437
438namespace {
439
440class FinalOverriderCollector {
441 /// The number of subobjects of a given class type that
442 /// occur within the class hierarchy.
443 llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;
444
445 /// Overriders for each virtual base subobject.
446 llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;
447
448 CXXFinalOverriderMap FinalOverriders;
449
450public:
451 ~FinalOverriderCollector();
452
453 void Collect(const CXXRecordDecl *RD, bool VirtualBase,
454 const CXXRecordDecl *InVirtualSubobject,
455 CXXFinalOverriderMap &Overriders);
456};
457
458} // namespace
459
460void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,
461 bool VirtualBase,
462 const CXXRecordDecl *InVirtualSubobject,
463 CXXFinalOverriderMap &Overriders) {
464 unsigned SubobjectNumber = 0;
465 if (!VirtualBase)
466 SubobjectNumber
467 = ++SubobjectCount[cast<CXXRecordDecl>(Val: RD->getCanonicalDecl())];
468
469 for (const auto &Base : RD->bases()) {
470 if (const RecordType *RT = Base.getType()->getAs<RecordType>()) {
471 const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(Val: RT->getDecl());
472 if (!BaseDecl->isPolymorphic())
473 continue;
474
475 if (Overriders.empty() && !Base.isVirtual()) {
476 // There are no other overriders of virtual member functions,
477 // so let the base class fill in our overriders for us.
478 Collect(RD: BaseDecl, VirtualBase: false, InVirtualSubobject, Overriders);
479 continue;
480 }
481
482 // Collect all of the overridders from the base class subobject
483 // and merge them into the set of overridders for this class.
484 // For virtual base classes, populate or use the cached virtual
485 // overrides so that we do not walk the virtual base class (and
486 // its base classes) more than once.
487 CXXFinalOverriderMap ComputedBaseOverriders;
488 CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;
489 if (Base.isVirtual()) {
490 CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];
491 BaseOverriders = MyVirtualOverriders;
492 if (!MyVirtualOverriders) {
493 MyVirtualOverriders = new CXXFinalOverriderMap;
494
495 // Collect may cause VirtualOverriders to reallocate, invalidating the
496 // MyVirtualOverriders reference. Set BaseOverriders to the right
497 // value now.
498 BaseOverriders = MyVirtualOverriders;
499
500 Collect(RD: BaseDecl, VirtualBase: true, InVirtualSubobject: BaseDecl, Overriders&: *MyVirtualOverriders);
501 }
502 } else
503 Collect(RD: BaseDecl, VirtualBase: false, InVirtualSubobject, Overriders&: ComputedBaseOverriders);
504
505 // Merge the overriders from this base class into our own set of
506 // overriders.
507 for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),
508 OMEnd = BaseOverriders->end();
509 OM != OMEnd;
510 ++OM) {
511 const CXXMethodDecl *CanonOM = OM->first->getCanonicalDecl();
512 Overriders[CanonOM].add(Other: OM->second);
513 }
514 }
515 }
516
517 for (auto *M : RD->methods()) {
518 // We only care about virtual methods.
519 if (!M->isVirtual())
520 continue;
521
522 CXXMethodDecl *CanonM = M->getCanonicalDecl();
523 using OverriddenMethodsRange =
524 llvm::iterator_range<CXXMethodDecl::method_iterator>;
525 OverriddenMethodsRange OverriddenMethods = CanonM->overridden_methods();
526
527 if (OverriddenMethods.begin() == OverriddenMethods.end()) {
528 // This is a new virtual function that does not override any
529 // other virtual function. Add it to the map of virtual
530 // functions for which we are tracking overridders.
531
532 // C++ [class.virtual]p2:
533 // For convenience we say that any virtual function overrides itself.
534 Overriders[CanonM].add(OverriddenSubobject: SubobjectNumber,
535 Overriding: UniqueVirtualMethod(CanonM, SubobjectNumber,
536 InVirtualSubobject));
537 continue;
538 }
539
540 // This virtual method overrides other virtual methods, so it does
541 // not add any new slots into the set of overriders. Instead, we
542 // replace entries in the set of overriders with the new
543 // overrider. To do so, we dig down to the original virtual
544 // functions using data recursion and update all of the methods it
545 // overrides.
546 SmallVector<OverriddenMethodsRange, 4> Stack(1, OverriddenMethods);
547 while (!Stack.empty()) {
548 for (const CXXMethodDecl *OM : Stack.pop_back_val()) {
549 const CXXMethodDecl *CanonOM = OM->getCanonicalDecl();
550
551 // C++ [class.virtual]p2:
552 // A virtual member function C::vf of a class object S is
553 // a final overrider unless the most derived class (1.8)
554 // of which S is a base class subobject (if any) declares
555 // or inherits another member function that overrides vf.
556 //
557 // Treating this object like the most derived class, we
558 // replace any overrides from base classes with this
559 // overriding virtual function.
560 Overriders[CanonOM].replaceAll(
561 Overriding: UniqueVirtualMethod(CanonM, SubobjectNumber,
562 InVirtualSubobject));
563
564 auto OverriddenMethods = CanonOM->overridden_methods();
565 if (OverriddenMethods.begin() == OverriddenMethods.end())
566 continue;
567
568 // Continue recursion to the methods that this virtual method
569 // overrides.
570 Stack.push_back(Elt: OverriddenMethods);
571 }
572 }
573
574 // C++ [class.virtual]p2:
575 // For convenience we say that any virtual function overrides itself.
576 Overriders[CanonM].add(OverriddenSubobject: SubobjectNumber,
577 Overriding: UniqueVirtualMethod(CanonM, SubobjectNumber,
578 InVirtualSubobject));
579 }
580}
581
582FinalOverriderCollector::~FinalOverriderCollector() {
583 for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator
584 VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();
585 VO != VOEnd;
586 ++VO)
587 delete VO->second;
588}
589
590void
591CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {
592 FinalOverriderCollector Collector;
593 Collector.Collect(RD: this, VirtualBase: false, InVirtualSubobject: nullptr, Overriders&: FinalOverriders);
594
595 // Weed out any final overriders that come from virtual base class
596 // subobjects that were hidden by other subobjects along any path.
597 // This is the final-overrider variant of C++ [class.member.lookup]p10.
598 for (auto &OM : FinalOverriders) {
599 for (auto &SO : OM.second) {
600 SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO.second;
601 if (Overriding.size() < 2)
602 continue;
603
604 auto IsHidden = [&Overriding](const UniqueVirtualMethod &M) {
605 if (!M.InVirtualSubobject)
606 return false;
607
608 // We have an overriding method in a virtual base class
609 // subobject (or non-virtual base class subobject thereof);
610 // determine whether there exists an other overriding method
611 // in a base class subobject that hides the virtual base class
612 // subobject.
613 for (const UniqueVirtualMethod &OP : Overriding)
614 if (&M != &OP &&
615 OP.Method->getParent()->isVirtuallyDerivedFrom(
616 Base: M.InVirtualSubobject))
617 return true;
618 return false;
619 };
620
621 // FIXME: IsHidden reads from Overriding from the middle of a remove_if
622 // over the same sequence! Is this guaranteed to work?
623 llvm::erase_if(C&: Overriding, P: IsHidden);
624 }
625 }
626}
627
628static void
629AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,
630 CXXIndirectPrimaryBaseSet& Bases) {
631 // If the record has a virtual primary base class, add it to our set.
632 const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
633 if (Layout.isPrimaryBaseVirtual())
634 Bases.insert(Ptr: Layout.getPrimaryBase());
635
636 for (const auto &I : RD->bases()) {
637 assert(!I.getType()->isDependentType() &&
638 "Cannot get indirect primary bases for class with dependent bases.");
639
640 const CXXRecordDecl *BaseDecl =
641 cast<CXXRecordDecl>(Val: I.getType()->getAsRecordDecl());
642
643 // Only bases with virtual bases participate in computing the
644 // indirect primary virtual base classes.
645 if (BaseDecl->getNumVBases())
646 AddIndirectPrimaryBases(RD: BaseDecl, Context, Bases);
647 }
648
649}
650
651void
652CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {
653 ASTContext &Context = getASTContext();
654
655 if (!getNumVBases())
656 return;
657
658 for (const auto &I : bases()) {
659 assert(!I.getType()->isDependentType() &&
660 "Cannot get indirect primary bases for class with dependent bases.");
661
662 const CXXRecordDecl *BaseDecl =
663 cast<CXXRecordDecl>(Val: I.getType()->getAsRecordDecl());
664
665 // Only bases with virtual bases participate in computing the
666 // indirect primary virtual base classes.
667 if (BaseDecl->getNumVBases())
668 AddIndirectPrimaryBases(RD: BaseDecl, Context, Bases);
669 }
670}
671

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of clang/lib/AST/CXXInheritance.cpp