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