diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2015-02-19 04:28:23 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2015-02-19 04:28:23 +0000 |
commit | df4a627fcd356fdc580ffa14be00424a26e82848 (patch) | |
tree | 9cc375e18041d107a37a930fc2a1832d5dc05eb9 | |
parent | 40e06d7fc7a7c9630cdfd2626322e4701500f7ab (diff) | |
download | clang-df4a627fcd356fdc580ffa14be00424a26e82848.tar.gz |
[MSVC] Improved lookup into dependent/non-dependent bases of dependent class
Patch improves lookup into dependendt bases of dependent class and adds lookup
into non-dependent bases.
Differential Revision: http://reviews.llvm.org/D7173
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@229817 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 104 | ||||
-rw-r--r-- | test/SemaTemplate/ms-lookup-template-base-classes.cpp | 69 |
2 files changed, 135 insertions, 38 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index fd8b3e5431..e2547739f4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -128,45 +128,85 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { return false; } +namespace { +enum class UnqualifiedTypeNameLookupResult { + NotFound, + FoundNonType, + FoundType +}; +} // namespace + +/// \brief Tries to perform unqualified lookup of the type decls in bases for +/// dependent class. +/// \return \a NotFound if no any decls is found, \a FoundNotType if found not a +/// type decl, \a FoundType if only type decls are found. +static UnqualifiedTypeNameLookupResult +lookupUnqualifiedTypeNameInBase(Sema &S, const IdentifierInfo &II, + SourceLocation NameLoc, + const CXXRecordDecl *RD) { + if (!RD->hasDefinition()) + return UnqualifiedTypeNameLookupResult::NotFound; + // Look for type decls in base classes. + UnqualifiedTypeNameLookupResult FoundTypeDecl = + UnqualifiedTypeNameLookupResult::NotFound; + for (const auto &Base : RD->bases()) { + const CXXRecordDecl *BaseRD = nullptr; + if (auto *BaseTT = Base.getType()->getAs<TagType>()) + BaseRD = BaseTT->getAsCXXRecordDecl(); + else if (auto *TST = Base.getType()->getAs<TemplateSpecializationType>()) { + // Look for type decls in dependent base classes that have known primary + // templates. + if (!TST || !TST->isDependentType()) + continue; + auto *TD = TST->getTemplateName().getAsTemplateDecl(); + if (!TD) + continue; + auto *BasePrimaryTemplate = + dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl()); + if (!BasePrimaryTemplate) + continue; + BaseRD = BasePrimaryTemplate; + } + if (BaseRD) { + for (NamedDecl *ND : BaseRD->lookup(&II)) { + if (!isa<TypeDecl>(ND)) + return UnqualifiedTypeNameLookupResult::FoundNonType; + FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType; + } + if (FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound) { + switch (lookupUnqualifiedTypeNameInBase(S, II, NameLoc, BaseRD)) { + case UnqualifiedTypeNameLookupResult::FoundNonType: + return UnqualifiedTypeNameLookupResult::FoundNonType; + case UnqualifiedTypeNameLookupResult::FoundType: + FoundTypeDecl = UnqualifiedTypeNameLookupResult::FoundType; + break; + case UnqualifiedTypeNameLookupResult::NotFound: + break; + } + } + } + } + + return FoundTypeDecl; +} + static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, const IdentifierInfo &II, SourceLocation NameLoc) { - // Find the first parent class template context, if any. - // FIXME: Perform the lookup in all enclosing class templates. + // Lookup in the parent class template context, if any. const CXXRecordDecl *RD = nullptr; - for (DeclContext *DC = S.CurContext; DC; DC = DC->getParent()) { + UnqualifiedTypeNameLookupResult FoundTypeDecl = + UnqualifiedTypeNameLookupResult::NotFound; + for (DeclContext *DC = S.CurContext; + DC && FoundTypeDecl == UnqualifiedTypeNameLookupResult::NotFound; + DC = DC->getParent()) { + // Look for type decls in dependent base classes that have known primary + // templates. RD = dyn_cast<CXXRecordDecl>(DC); if (RD && RD->getDescribedClassTemplate()) - break; - } - if (!RD) - return ParsedType(); - - // Look for type decls in dependent base classes that have known primary - // templates. - bool FoundTypeDecl = false; - for (const auto &Base : RD->bases()) { - auto *TST = Base.getType()->getAs<TemplateSpecializationType>(); - if (!TST || !TST->isDependentType()) - continue; - auto *TD = TST->getTemplateName().getAsTemplateDecl(); - if (!TD) - continue; - auto *BasePrimaryTemplate = - dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl()); - if (!BasePrimaryTemplate) - continue; - // FIXME: Allow lookup into non-dependent bases of dependent bases, possibly - // by calling or integrating with the main LookupQualifiedName mechanism. - for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) { - if (FoundTypeDecl) - return ParsedType(); - FoundTypeDecl = isa<TypeDecl>(ND); - if (!FoundTypeDecl) - return ParsedType(); - } + FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD); } - if (!FoundTypeDecl) + if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType) return ParsedType(); // We found some types in dependent base classes. Recover as if the user diff --git a/test/SemaTemplate/ms-lookup-template-base-classes.cpp b/test/SemaTemplate/ms-lookup-template-base-classes.cpp index 979782f1cb..62451081c3 100644 --- a/test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ b/test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -303,12 +303,12 @@ static_assert(sizeof(B<int>) == sizeof(A<int>::NameFromBase), ""); } namespace two_types_in_base { -template <typename T> struct A { typedef T NameFromBase; }; -template <typename T> struct B { struct NameFromBase { T m; }; }; +template <typename T> struct A { typedef T NameFromBase; }; // expected-note {{member found by ambiguous name lookup}} +template <typename T> struct B { struct NameFromBase { T m; }; }; // expected-note {{member found by ambiguous name lookup}} template <typename T> struct C : A<T>, B<T> { - NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} + NameFromBase m; // expected-error {{member 'NameFromBase' found in multiple base classes of different types}} expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} }; -static_assert(sizeof(C<int>) == 4, ""); +static_assert(sizeof(C<int>) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C<int>' requested here}} } namespace type_and_decl_in_base { @@ -386,9 +386,66 @@ namespace type_in_base_of_dependent_base { struct A { typedef int NameFromBase; }; template <typename T> struct B : A {}; -// FIXME: MSVC accepts this. template <typename T> -struct C : B<T> { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}} +struct C : B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} +} + +namespace type_in_second_dependent_base { +template <typename T> +struct A {}; +template<typename T> +struct B { typedef T NameFromBase; }; +template <typename T> +struct D : A<T>, B<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} +} + +namespace type_in_second_non_dependent_base { +struct A {}; +struct B { typedef int NameFromBase; }; +template<typename T> +struct C : A, B {}; +template <typename T> +struct D : C<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} +} + +namespace type_in_virtual_base_of_dependent_base { +template <typename T> +struct A { typedef T NameFromBase; }; +template <typename T> +struct B : virtual A<T> {}; +template <typename T> +struct C : B<T>, virtual A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} +C<int> c; +} + +namespace type_in_base_of_multiple_dependent_bases { +template <typename T> +struct A { typedef T NameFromBase; }; +template <typename T> +struct B : public A<T> {}; +template <typename T> +struct C : B<T>, public A<T> { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} expected-warning {{direct base 'A<int>' is inaccessible due to ambiguity:}} +C<int> c; // expected-note {{in instantiation of template class 'type_in_base_of_multiple_dependent_bases::C<int>' requested here}} +} + +namespace type_in_dependent_base_of_non_dependent_type { +template<typename T> struct A { typedef int NameFromBase; }; +template<typename T> struct B : A<T> { + struct C; + template<typename TT> + struct D : C { + NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} + }; + struct E : C { + NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} + }; +}; +template<typename T> struct B<T>::C : B { + NameFromBase m; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} +}; +template<typename T> struct F : B<T>::C { + NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} +}; } namespace lookup_in_function_contexts { |