brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.0 KiB · 29f5916 Raw
659 lines · cpp
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-exception6//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 is34/// ambiguous, i.e., there are two or more paths that refer to35/// different base class subobjects of the same type. BaseType must be36/// an unqualified, canonical class type.37bool CXXBasePaths::isAmbiguous(CanQualType BaseType) const {38  BaseType = BaseType.getUnqualifiedType();39  IsVirtBaseAndNumberNonVirtBases Subobjects = ClassSubobjects.lookup(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 the53/// contents of Other.54void CXXBasePaths::swap(CXXBasePaths &Other) {55  std::swap(Origin, Other.Origin);56  Paths.swap(Other.Paths);57  ClassSubobjects.swap(Other.ClassSubobjects);58  VisitedDependentRecords.swap(Other.VisitedDependentRecords);59  std::swap(FindAmbiguities, Other.FindAmbiguities);60  std::swap(RecordPaths, Other.RecordPaths);61  std::swap(DetectVirtual, Other.DetectVirtual);62  std::swap(DetectedVirtual, 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      [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {81        return Specifier->getType()->getAsRecordDecl() &&82               FindBaseClass(Specifier, Path, 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      [BaseDecl](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {102        return FindVirtualBaseClass(Specifier, Path, BaseDecl);103      },104      Paths);105}106 107bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const {108  const CXXRecordDecl *TargetDecl = Base->getCanonicalDecl();109  return forallBases([TargetDecl](const CXXRecordDecl *Base) {110    return Base->getCanonicalDecl() != TargetDecl;111  });112}113 114bool115CXXRecordDecl::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 auto *Base = I.getType()->getAsCXXRecordDecl();132      if (!Base || !(Base->isBeingDefined() || Base->isCompleteDefinition()))133        return false;134      if (Base->isDependentContext() && !Base->isCurrentInstantiation(Record))135        return false;136 137      Queue.push_back(Base);138      if (!BaseMatches(Base))139        return false;140    }141 142    if (Queue.empty())143      break;144    Record = Queue.pop_back_val(); // not actually a queue.145  }146 147  return true;148}149 150bool CXXBasePaths::lookupInBases(ASTContext &Context,151                                 const CXXRecordDecl *Record,152                                 CXXRecordDecl::BaseMatchesCallback BaseMatches,153                                 bool LookupInDependent) {154  bool FoundPath = false;155 156  // The access of the path down to this record.157  AccessSpecifier AccessToHere = ScratchPath.Access;158  bool IsFirstStep = ScratchPath.empty();159 160  for (const auto &BaseSpec : Record->bases()) {161    // Find the record of the base class subobjects for this type.162    QualType BaseType =163        Context.getCanonicalType(BaseSpec.getType()).getUnqualifiedType();164 165    bool isCurrentInstantiation = isa<InjectedClassNameType>(BaseType);166    if (!isCurrentInstantiation) {167      if (auto *BaseRecord = cast_if_present<CXXRecordDecl>(168              BaseSpec.getType()->getAsRecordDecl()))169        isCurrentInstantiation = BaseRecord->isDependentContext() &&170                                 BaseRecord->isCurrentInstantiation(Record);171    }172    // C++ [temp.dep]p3:173    //   In the definition of a class template or a member of a class template,174    //   if a base class of the class template depends on a template-parameter,175    //   the base class scope is not examined during unqualified name lookup176    //   either at the point of definition of the class template or member or177    //   during an instantiation of the class tem- plate or member.178    if (!LookupInDependent &&179        (BaseType->isDependentType() && !isCurrentInstantiation))180      continue;181 182    // Determine whether we need to visit this base class at all,183    // updating the count of subobjects appropriately.184    IsVirtBaseAndNumberNonVirtBases &Subobjects = ClassSubobjects[BaseType];185    bool VisitBase = true;186    bool SetVirtual = false;187    if (BaseSpec.isVirtual()) {188      VisitBase = !Subobjects.IsVirtBase;189      Subobjects.IsVirtBase = true;190      if (isDetectingVirtual() && DetectedVirtual == nullptr) {191        // If this is the first virtual we find, remember it. If it turns out192        // there is no base path here, we'll reset it later.193        DetectedVirtual = BaseType->getAsCanonical<RecordType>();194        SetVirtual = true;195      }196    } else {197      ++Subobjects.NumberOfNonVirtBases;198    }199    if (isRecordingPaths()) {200      // Add this base specifier to the current path.201      CXXBasePathElement Element;202      Element.Base = &BaseSpec;203      Element.Class = Record;204      if (BaseSpec.isVirtual())205        Element.SubobjectNumber = 0;206      else207        Element.SubobjectNumber = Subobjects.NumberOfNonVirtBases;208      ScratchPath.push_back(Element);209 210      // Calculate the "top-down" access to this base class.211      // The spec actually describes this bottom-up, but top-down is212      // equivalent because the definition works out as follows:213      // 1. Write down the access along each step in the inheritance214      //    chain, followed by the access of the decl itself.215      //    For example, in216      //      class A { public: int foo; };217      //      class B : protected A {};218      //      class C : public B {};219      //      class D : private C {};220      //    we would write:221      //      private public protected public222      // 2. If 'private' appears anywhere except far-left, access is denied.223      // 3. Otherwise, overall access is determined by the most restrictive224      //    access in the sequence.225      if (IsFirstStep)226        ScratchPath.Access = BaseSpec.getAccessSpecifier();227      else228        ScratchPath.Access = CXXRecordDecl::MergeAccess(AccessToHere,229                                                 BaseSpec.getAccessSpecifier());230    }231 232    // Track whether there's a path involving this specific base.233    bool FoundPathThroughBase = false;234 235    if (BaseMatches(&BaseSpec, ScratchPath)) {236      // We've found a path that terminates at this base.237      FoundPath = FoundPathThroughBase = true;238      if (isRecordingPaths()) {239        // We have a path. Make a copy of it before moving on.240        Paths.push_back(ScratchPath);241      } else if (!isFindingAmbiguities()) {242        // We found a path and we don't care about ambiguities;243        // return immediately.244        return FoundPath;245      }246    } else if (VisitBase) {247      CXXRecordDecl *BaseRecord = nullptr;248      if (LookupInDependent) {249        const TemplateSpecializationType *TST =250            BaseSpec.getType()->getAs<TemplateSpecializationType>();251        if (!TST) {252          BaseRecord = BaseSpec.getType()->getAsCXXRecordDecl();253        } else {254          TemplateName TN = TST->getTemplateName();255          if (auto *TD =256                  dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl()))257            BaseRecord = TD->getTemplatedDecl();258        }259        if (BaseRecord) {260          if (!BaseRecord->hasDefinition())261            BaseRecord = nullptr;262          else if (!VisitedDependentRecords.insert(BaseRecord).second)263            BaseRecord = nullptr;264        }265      } else {266        BaseRecord = BaseSpec.getType()->castAsCXXRecordDecl();267      }268      if (BaseRecord &&269          lookupInBases(Context, BaseRecord, BaseMatches, LookupInDependent)) {270        // C++ [class.member.lookup]p2:271        //   A member name f in one sub-object B hides a member name f in272        //   a sub-object A if A is a base class sub-object of B. Any273        //   declarations that are so hidden are eliminated from274        //   consideration.275 276        // There is a path to a base class that meets the criteria. If we're277        // not collecting paths or finding ambiguities, we're done.278        FoundPath = FoundPathThroughBase = true;279        if (!isFindingAmbiguities())280          return FoundPath;281      }282    }283 284    // Pop this base specifier off the current path (if we're285    // collecting paths).286    if (isRecordingPaths()) {287      ScratchPath.pop_back();288    }289 290    // If we set a virtual earlier, and this isn't a path, forget it again.291    if (SetVirtual && !FoundPathThroughBase) {292      DetectedVirtual = nullptr;293    }294  }295 296  // Reset the scratch path access.297  ScratchPath.Access = AccessToHere;298 299  return FoundPath;300}301 302bool CXXRecordDecl::lookupInBases(BaseMatchesCallback BaseMatches,303                                  CXXBasePaths &Paths,304                                  bool LookupInDependent) const {305  // If we didn't find anything, report that.306  if (!Paths.lookupInBases(getASTContext(), this, BaseMatches,307                           LookupInDependent))308    return false;309 310  // If we're not recording paths or we won't ever find ambiguities,311  // we're done.312  if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities())313    return true;314 315  // C++ [class.member.lookup]p6:316  //   When virtual base classes are used, a hidden declaration can be317  //   reached along a path through the sub-object lattice that does318  //   not pass through the hiding declaration. This is not an319  //   ambiguity. The identical use with nonvirtual base classes is an320  //   ambiguity; in that case there is no unique instance of the name321  //   that hides all the others.322  //323  // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy324  // way to make it any faster.325  Paths.Paths.remove_if([&Paths](const CXXBasePath &Path) {326    for (const CXXBasePathElement &PE : Path) {327      if (!PE.Base->isVirtual())328        continue;329 330      auto *VBase = PE.Base->getType()->getAsCXXRecordDecl();331      if (!VBase)332        break;333 334      // The declaration(s) we found along this path were found in a335      // subobject of a virtual base. Check whether this virtual336      // base is a subobject of any other path; if so, then the337      // declaration in this path are hidden by that patch.338      for (const CXXBasePath &HidingP : Paths) {339        auto *HidingClass =340            HidingP.back().Base->getType()->getAsCXXRecordDecl();341        if (!HidingClass)342          break;343 344        if (HidingClass->isVirtuallyDerivedFrom(VBase))345          return true;346      }347    }348    return false;349  });350 351  return true;352}353 354bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier,355                                  CXXBasePath &Path,356                                  const CXXRecordDecl *BaseRecord) {357  assert(BaseRecord->getCanonicalDecl() == BaseRecord &&358         "User data for FindBaseClass is not canonical!");359  return cast<CXXRecordDecl>(Specifier->getType()->getAsRecordDecl())360             ->getCanonicalDecl() == BaseRecord;361}362 363bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier,364                                         CXXBasePath &Path,365                                         const CXXRecordDecl *BaseRecord) {366  assert(BaseRecord->getCanonicalDecl() == BaseRecord &&367         "User data for FindBaseClass is not canonical!");368  return Specifier->isVirtual() &&369         cast<CXXRecordDecl>(Specifier->getType()->getAsRecordDecl())370                 ->getCanonicalDecl() == BaseRecord;371}372 373static bool isOrdinaryMember(const NamedDecl *ND) {374  return ND->isInIdentifierNamespace(Decl::IDNS_Ordinary | Decl::IDNS_Tag |375                                     Decl::IDNS_Member);376}377 378static bool findOrdinaryMember(const CXXRecordDecl *RD, CXXBasePath &Path,379                               DeclarationName Name) {380  Path.Decls = RD->lookup(Name).begin();381  for (DeclContext::lookup_iterator I = Path.Decls, E = I.end(); I != E; ++I)382    if (isOrdinaryMember(*I))383      return true;384 385  return false;386}387 388bool CXXRecordDecl::hasMemberName(DeclarationName Name) const {389  CXXBasePath P;390  if (findOrdinaryMember(this, P, Name))391    return true;392 393  CXXBasePaths Paths(false, false, false);394  return lookupInBases(395      [Name](const CXXBaseSpecifier *Specifier, CXXBasePath &Path) {396        return findOrdinaryMember(Specifier->getType()->castAsCXXRecordDecl(),397                                  Path, Name);398      },399      Paths);400}401 402void OverridingMethods::add(unsigned OverriddenSubobject,403                            UniqueVirtualMethod Overriding) {404  SmallVectorImpl<UniqueVirtualMethod> &SubobjectOverrides405    = Overrides[OverriddenSubobject];406  if (!llvm::is_contained(SubobjectOverrides, Overriding))407    SubobjectOverrides.push_back(Overriding);408}409 410void OverridingMethods::add(const OverridingMethods &Other) {411  for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) {412    for (overriding_const_iterator M = I->second.begin(),413                                MEnd = I->second.end();414         M != MEnd;415         ++M)416      add(I->first, *M);417  }418}419 420void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) {421  for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) {422    I->second.clear();423    I->second.push_back(Overriding);424  }425}426 427namespace {428 429class FinalOverriderCollector {430  /// The number of subobjects of a given class type that431  /// occur within the class hierarchy.432  llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount;433 434  /// Overriders for each virtual base subobject.435  llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders;436 437  CXXFinalOverriderMap FinalOverriders;438 439public:440  ~FinalOverriderCollector();441 442  void Collect(const CXXRecordDecl *RD, bool VirtualBase,443               const CXXRecordDecl *InVirtualSubobject,444               CXXFinalOverriderMap &Overriders);445};446 447} // namespace448 449void FinalOverriderCollector::Collect(const CXXRecordDecl *RD,450                                      bool VirtualBase,451                                      const CXXRecordDecl *InVirtualSubobject,452                                      CXXFinalOverriderMap &Overriders) {453  unsigned SubobjectNumber = 0;454  if (!VirtualBase)455    SubobjectNumber456      = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())];457 458  for (const auto &Base : RD->bases()) {459    if (const auto *BaseDecl = Base.getType()->getAsCXXRecordDecl()) {460      if (!BaseDecl->isPolymorphic())461        continue;462 463      if (Overriders.empty() && !Base.isVirtual()) {464        // There are no other overriders of virtual member functions,465        // so let the base class fill in our overriders for us.466        Collect(BaseDecl, false, InVirtualSubobject, Overriders);467        continue;468      }469 470      // Collect all of the overridders from the base class subobject471      // and merge them into the set of overridders for this class.472      // For virtual base classes, populate or use the cached virtual473      // overrides so that we do not walk the virtual base class (and474      // its base classes) more than once.475      CXXFinalOverriderMap ComputedBaseOverriders;476      CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders;477      if (Base.isVirtual()) {478        CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl];479        BaseOverriders = MyVirtualOverriders;480        if (!MyVirtualOverriders) {481          MyVirtualOverriders = new CXXFinalOverriderMap;482 483          // Collect may cause VirtualOverriders to reallocate, invalidating the484          // MyVirtualOverriders reference. Set BaseOverriders to the right485          // value now.486          BaseOverriders = MyVirtualOverriders;487 488          Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders);489        }490      } else491        Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders);492 493      // Merge the overriders from this base class into our own set of494      // overriders.495      for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(),496                               OMEnd = BaseOverriders->end();497           OM != OMEnd;498           ++OM) {499        const CXXMethodDecl *CanonOM = OM->first->getCanonicalDecl();500        Overriders[CanonOM].add(OM->second);501      }502    }503  }504 505  for (auto *M : RD->methods()) {506    // We only care about virtual methods.507    if (!M->isVirtual())508      continue;509 510    CXXMethodDecl *CanonM = M->getCanonicalDecl();511    using OverriddenMethodsRange =512        llvm::iterator_range<CXXMethodDecl::method_iterator>;513    OverriddenMethodsRange OverriddenMethods = CanonM->overridden_methods();514 515    if (OverriddenMethods.begin() == OverriddenMethods.end()) {516      // This is a new virtual function that does not override any517      // other virtual function. Add it to the map of virtual518      // functions for which we are tracking overridders.519 520      // C++ [class.virtual]p2:521      //   For convenience we say that any virtual function overrides itself.522      Overriders[CanonM].add(SubobjectNumber,523                             UniqueVirtualMethod(CanonM, SubobjectNumber,524                                                 InVirtualSubobject));525      continue;526    }527 528    // This virtual method overrides other virtual methods, so it does529    // not add any new slots into the set of overriders. Instead, we530    // replace entries in the set of overriders with the new531    // overrider. To do so, we dig down to the original virtual532    // functions using data recursion and update all of the methods it533    // overrides.534    SmallVector<OverriddenMethodsRange, 4> Stack(1, OverriddenMethods);535    while (!Stack.empty()) {536      for (const CXXMethodDecl *OM : Stack.pop_back_val()) {537        const CXXMethodDecl *CanonOM = OM->getCanonicalDecl();538 539        // C++ [class.virtual]p2:540        //   A virtual member function C::vf of a class object S is541        //   a final overrider unless the most derived class (1.8)542        //   of which S is a base class subobject (if any) declares543        //   or inherits another member function that overrides vf.544        //545        // Treating this object like the most derived class, we546        // replace any overrides from base classes with this547        // overriding virtual function.548        Overriders[CanonOM].replaceAll(549                               UniqueVirtualMethod(CanonM, SubobjectNumber,550                                                   InVirtualSubobject));551 552        auto OverriddenMethods = CanonOM->overridden_methods();553        if (OverriddenMethods.begin() == OverriddenMethods.end())554          continue;555 556        // Continue recursion to the methods that this virtual method557        // overrides.558        Stack.push_back(OverriddenMethods);559      }560    }561 562    // C++ [class.virtual]p2:563    //   For convenience we say that any virtual function overrides itself.564    Overriders[CanonM].add(SubobjectNumber,565                           UniqueVirtualMethod(CanonM, SubobjectNumber,566                                               InVirtualSubobject));567  }568}569 570FinalOverriderCollector::~FinalOverriderCollector() {571  for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator572         VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end();573       VO != VOEnd;574       ++VO)575    delete VO->second;576}577 578void579CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const {580  FinalOverriderCollector Collector;581  Collector.Collect(this, false, nullptr, FinalOverriders);582 583  // Weed out any final overriders that come from virtual base class584  // subobjects that were hidden by other subobjects along any path.585  // This is the final-overrider variant of C++ [class.member.lookup]p10.586  for (auto &OM : FinalOverriders) {587    for (auto &SO : OM.second) {588      SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO.second;589      if (Overriding.size() < 2)590        continue;591 592      auto IsHidden = [&Overriding](const UniqueVirtualMethod &M) {593        if (!M.InVirtualSubobject)594          return false;595 596        // We have an overriding method in a virtual base class597        // subobject (or non-virtual base class subobject thereof);598        // determine whether there exists an other overriding method599        // in a base class subobject that hides the virtual base class600        // subobject.601        for (const UniqueVirtualMethod &OP : Overriding)602          if (&M != &OP &&603              OP.Method->getParent()->isVirtuallyDerivedFrom(604                  M.InVirtualSubobject))605            return true;606        return false;607      };608 609      // FIXME: IsHidden reads from Overriding from the middle of a remove_if610      // over the same sequence! Is this guaranteed to work?611      llvm::erase_if(Overriding, IsHidden);612    }613  }614}615 616static void617AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context,618                        CXXIndirectPrimaryBaseSet& Bases) {619  // If the record has a virtual primary base class, add it to our set.620  const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);621  if (Layout.isPrimaryBaseVirtual())622    Bases.insert(Layout.getPrimaryBase());623 624  for (const auto &I : RD->bases()) {625    assert(!I.getType()->isDependentType() &&626           "Cannot get indirect primary bases for class with dependent bases.");627 628    const CXXRecordDecl *BaseDecl =629        cast<CXXRecordDecl>(I.getType()->getAsRecordDecl());630 631    // Only bases with virtual bases participate in computing the632    // indirect primary virtual base classes.633    if (BaseDecl->getNumVBases())634      AddIndirectPrimaryBases(BaseDecl, Context, Bases);635  }636 637}638 639void640CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const {641  ASTContext &Context = getASTContext();642 643  if (!getNumVBases())644    return;645 646  for (const auto &I : bases()) {647    assert(!I.getType()->isDependentType() &&648           "Cannot get indirect primary bases for class with dependent bases.");649 650    const CXXRecordDecl *BaseDecl =651        cast<CXXRecordDecl>(I.getType()->getAsRecordDecl());652 653    // Only bases with virtual bases participate in computing the654    // indirect primary virtual base classes.655    if (BaseDecl->getNumVBases())656      AddIndirectPrimaryBases(BaseDecl, Context, Bases);657  }658}659