From 229d47aef27e6f65fe4dc3beb22f622dd81104ad Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Sat, 10 Nov 2012 07:24:09 +0000 Subject: [PATCH] Rework my implementation of circular-reference finding to not use CXXRecordDecl::forallBases, which does *not* do what I need. Fixes the failure introduced in r167651. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167668 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 6 +--- lib/AST/CXXInheritance.cpp | 10 +++---- lib/Sema/SemaDeclCXX.cpp | 41 ++++++++++++++++++++++----- test/SemaTemplate/dependent-names.cpp | 3 ++ 4 files changed, 43 insertions(+), 17 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index d5d66fcd96..9cb56e2b3c 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -1322,12 +1322,8 @@ public: /// \param AllowShortCircuit if false, forces the callback to be called /// for every base class, even if a dependent or non-matching base was /// found. - /// - /// \param VisitDependent whether we should also visit dependent bases - /// that can be resolved to CXXRecordDecls. bool forallBases(ForallBasesCallback *BaseMatches, void *UserData, - bool AllowShortCircuit = true, - bool VisitDependent = false) const; + bool AllowShortCircuit = true) const; /// \brief Function type used by lookupInBases() to determine whether a /// specific base class subobject matches the lookup criteria. diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 6e91f3f910..213b214a4e 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -123,8 +123,7 @@ bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, void *OpaqueData, - bool AllowShortCircuit, - bool VisitDependent) const { + bool AllowShortCircuit) const { SmallVector Queue; const CXXRecordDecl *Record = this; @@ -132,14 +131,15 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, while (true) { for (CXXRecordDecl::base_class_const_iterator I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { - CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl(); - if (!Base || (!VisitDependent && I->getType()->isDependentType())) { + const RecordType *Ty = I->getType()->getAs(); + if (!Ty) { if (AllowShortCircuit) return false; AllMatches = false; continue; } - Base = Base->getDefinition(); + CXXRecordDecl *Base = + cast_or_null(Ty->getDecl()->getDefinition()); if (!Base) { if (AllowShortCircuit) return false; AllMatches = false; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 1c3d4f2052..16eddf80ae 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -1018,12 +1018,39 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, return false; } -/// \brief Determine whether we have the same C++ record definition. -/// -/// Used as a helper function in Sema::CheckBaseSpecifier, below. -static bool sameCXXRecordDef(const CXXRecordDecl *BaseDefinition, - void *UserData) { - return (CXXRecordDecl *)UserData != BaseDefinition; +/// \brief Determine whether the given class is a base class of the given +/// class, including looking at dependent bases. +static bool findCircularInheritance(const CXXRecordDecl *Class, + const CXXRecordDecl *Current) { + SmallVector Queue; + + Class = Class->getCanonicalDecl(); + while (true) { + for (CXXRecordDecl::base_class_const_iterator I = Current->bases_begin(), + E = Current->bases_end(); + I != E; ++I) { + CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl(); + if (!Base) + continue; + + Base = Base->getDefinition(); + if (!Base) + continue; + + if (Base->getCanonicalDecl() == Class) + return true; + + Queue.push_back(Base); + } + + if (Queue.empty()) + return false; + + Current = Queue.back(); + Queue.pop_back(); + } + + return false; } /// \brief Check the validity of a C++ base class specifier. @@ -1062,7 +1089,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, if (CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl()) { if (BaseDecl->getCanonicalDecl() == Class->getCanonicalDecl() || ((BaseDecl = BaseDecl->getDefinition()) && - !BaseDecl->forallBases(&sameCXXRecordDef, Class))) { + findCircularInheritance(Class, BaseDecl))) { Diag(BaseLoc, diag::err_circular_inheritance) << BaseType << Context.getTypeDeclType(Class); diff --git a/test/SemaTemplate/dependent-names.cpp b/test/SemaTemplate/dependent-names.cpp index 4e322d909d..efa4d28723 100644 --- a/test/SemaTemplate/dependent-names.cpp +++ b/test/SemaTemplate/dependent-names.cpp @@ -336,6 +336,9 @@ namespace rdar12629723 { virtual void foo() { } }; struct B; + + struct D : T::foo { }; + struct E : D { }; }; template -- 2.40.0