From d89d30fdd9e3061fb100fb8f976aab5c6cf2c901 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 28 Jan 2011 22:02:36 +0000 Subject: [PATCH] Fix some corner cases in the __is_base_of logic. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124505 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/DeclCXX.h | 4 +-- lib/AST/CXXInheritance.cpp | 9 ++++--- lib/Sema/SemaExprCXX.cpp | 47 +++++++++++++++++++++--------------- test/SemaCXX/type-traits.cpp | 12 ++++++++- 4 files changed, 46 insertions(+), 26 deletions(-) diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 8c66752f42..1d1b749feb 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -811,7 +811,7 @@ public: /// \param Base the base class we are searching for. /// /// \returns true if this class is derived from Base, false otherwise. - bool isDerivedFrom(CXXRecordDecl *Base) const; + bool isDerivedFrom(const CXXRecordDecl *Base) const; /// \brief Determine whether this class is derived from the type \p Base. /// @@ -829,7 +829,7 @@ public: /// /// \todo add a separate paramaeter to configure IsDerivedFrom, rather than /// tangling input and output in \p Paths - bool isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const; + bool isDerivedFrom(const CXXRecordDecl *Base, CXXBasePaths &Paths) const; /// \brief Determine whether this class is virtually derived from /// the class \p Base. diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 9853fc2bb2..ca9ec18b39 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -76,18 +76,21 @@ void CXXBasePaths::swap(CXXBasePaths &Other) { std::swap(DetectedVirtual, Other.DetectedVirtual); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const { CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, /*DetectVirtual=*/false); return isDerivedFrom(Base, Paths); } -bool CXXRecordDecl::isDerivedFrom(CXXRecordDecl *Base, CXXBasePaths &Paths) const { +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, + CXXBasePaths &Paths) const { if (getCanonicalDecl() == Base->getCanonicalDecl()) return false; Paths.setOrigin(const_cast(this)); - return lookupInBases(&FindBaseClass, Base->getCanonicalDecl(), Paths); + return lookupInBases(&FindBaseClass, + const_cast(Base->getCanonicalDecl()), + Paths); } bool CXXRecordDecl::isVirtuallyDerivedFrom(CXXRecordDecl *Base) const { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 6ba18a54fd..82e818fba0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2487,17 +2487,36 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, "Cannot evaluate traits for dependent types."); switch(BTT) { - case BTT_IsBaseOf: + case BTT_IsBaseOf: { // C++0x [meta.rel]p2 - // Base is a base class of Derived without regard to cv-qualifiers or + // Base is a base class of Derived without regard to cv-qualifiers or // Base and Derived are not unions and name the same class type without // regard to cv-qualifiers. - if (Self.IsDerivedFrom(RhsT, LhsT) || - (!LhsT->isUnionType() && !RhsT->isUnionType() - && LhsT->getAsCXXRecordDecl() == RhsT->getAsCXXRecordDecl())) - return true; - return false; + const RecordType *lhsRecord = LhsT->getAs(); + if (!lhsRecord) return false; + + const RecordType *rhsRecord = RhsT->getAs(); + if (!rhsRecord) return false; + + assert(Self.Context.hasSameUnqualifiedType(LhsT, RhsT) + == (lhsRecord == rhsRecord)); + + if (lhsRecord == rhsRecord) + return !lhsRecord->getDecl()->isUnion(); + + // C++0x [meta.rel]p2: + // If Base and Derived are class types and are different types + // (ignoring possible cv-qualifiers) then Derived shall be a + // complete type. + if (Self.RequireCompleteType(KeyLoc, RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) + return false; + + return cast(rhsRecord->getDecl()) + ->isDerivedFrom(cast(lhsRecord->getDecl())); + } + case BTT_TypeCompatible: return Self.Context.typesAreCompatible(LhsT.getUnqualifiedType(), RhsT.getUnqualifiedType()); @@ -2560,19 +2579,7 @@ ExprResult Sema::BuildBinaryTypeTrait(BinaryTypeTrait BTT, QualType LhsT = LhsTSInfo->getType(); QualType RhsT = RhsTSInfo->getType(); - if (BTT == BTT_IsBaseOf) { - // C++0x [meta.rel]p2 - // If Base and Derived are class types and are different types - // (ignoring possible cv-qualifiers) then Derived shall be a complete - // type. [] - CXXRecordDecl *LhsDecl = LhsT->getAsCXXRecordDecl(); - CXXRecordDecl *RhsDecl = RhsT->getAsCXXRecordDecl(); - if (!LhsT->isDependentType() && !RhsT->isDependentType() && - LhsDecl && RhsDecl && LhsT != RhsT && - RequireCompleteType(KWLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) - return ExprError(); - } else if (BTT == BTT_TypeCompatible) { + if (BTT == BTT_TypeCompatible) { if (getLangOptions().CPlusPlus) { Diag(KWLoc, diag::err_types_compatible_p_in_cplusplus) << SourceRange(KWLoc, RParen); diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index b7f18aa6bd..ff9a6bf51a 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -469,6 +469,9 @@ void isBaseOfF() { int t[F(__is_base_of(Base, Derived))]; }; +template class DerivedTemp : Base {}; +template class NonderivedTemp {}; +template class UndefinedTemp; // expected-note {{declared here}} void is_base_of() { int t01[T(__is_base_of(Base, Derived))]; @@ -486,7 +489,14 @@ void is_base_of() { int t13[F(__is_base_of(Union, Union))]; int t14[T(__is_base_of(Empty, Empty))]; int t15[T(__is_base_of(class_forward, class_forward))]; - int t16[F(__is_base_of(Empty, class_forward))]; // expected-error {{incomplete type 'class_forward' used in type trait expression}} + int t16[F(__is_base_of(Empty, class_forward))]; // expected-error {{incomplete type 'class_forward' used in type trait expression}} + int t17[F(__is_base_of(Base&, Derived&))]; + int t18[F(__is_base_of(Base[10], Derived[10]))]; + int t19[F(__is_base_of(int, int))]; + int t20[F(__is_base_of(long, int))]; + int t21[T(__is_base_of(Base, DerivedTemp))]; + int t22[F(__is_base_of(Base, NonderivedTemp))]; + int t23[F(__is_base_of(Base, UndefinedTemp))]; // expected-error {{implicit instantiation of undefined template 'UndefinedTemp'}} isBaseOfT(); isBaseOfF(); -- 2.50.1