Index: include/clang/AST/Type.h =================================================================== --- include/clang/AST/Type.h +++ include/clang/AST/Type.h @@ -3374,6 +3374,7 @@ public: TagDecl *getDecl() const; + TagDecl *getDecl(); /// @brief Determines whether this type is in the process of being /// defined. Index: lib/AST/Type.cpp =================================================================== --- lib/AST/Type.cpp +++ lib/AST/Type.cpp @@ -1895,6 +1895,10 @@ return getInterestingTagDecl(decl); } +TagDecl *TagType::getDecl() { + return getInterestingTagDecl(decl); +} + bool TagType::isBeingDefined() const { return getDecl()->isBeingDefined(); } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -128,45 +128,82 @@ return false; } +namespace { +enum BasesLookupResult { NotFound, FoundNotType, 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 BasesLookupResult lookupInBases(Sema &S, const IdentifierInfo &II, + SourceLocation NameLoc, + const CXXRecordDecl *RD) { + if (!RD || !RD->getDescribedClassTemplate()) + return NotFound; + + // Look for type decls in base classes. + BasesLookupResult FoundTypeDecl = NotFound; + for (const auto &Base : RD->bases()) { + if (auto *TT = Base.getType()->getAs()) { + // Look for type decls in non-dependent base classes. + if (auto *DC = dyn_cast(TT->getDecl())) { + LookupResult LR(S, DeclarationName(&II), NameLoc, + /*LookupKind=*/Sema::LookupAnyName); + if (!S.LookupQualifiedName(LR, DC) && + LR.getResultKind() == LookupResult::NotFound) + continue; + if (!LR.getAsSingle()) + return FoundNotType; + FoundTypeDecl = FoundType; + } + } else if (auto *TST = + Base.getType()->getAs()) { + // 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(TD->getTemplatedDecl()); + if (!BasePrimaryTemplate) + continue; + switch (lookupInBases(S, II, NameLoc, BasePrimaryTemplate)) { + case FoundNotType: + return FoundNotType; + case FoundType: + FoundTypeDecl = FoundType; + break; + case NotFound: + break; + } + for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) { + if (!isa(ND)) + return FoundNotType; + FoundTypeDecl = FoundType; + } + } + } + + 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. const CXXRecordDecl *RD = nullptr; for (DeclContext *DC = S.CurContext; DC; DC = DC->getParent()) { RD = dyn_cast(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(); - if (!TST || !TST->isDependentType()) - continue; - auto *TD = TST->getTemplateName().getAsTemplateDecl(); - if (!TD) - continue; - auto *BasePrimaryTemplate = - dyn_cast_or_null(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(ND); - if (!FoundTypeDecl) - return ParsedType(); - } - } - if (!FoundTypeDecl) + BasesLookupResult FoundTypeDecl = lookupInBases(S, II, NameLoc, RD); + if (FoundTypeDecl != FoundType) return ParsedType(); // We found some types in dependent base classes. Recover as if the user Index: test/SemaTemplate/ms-lookup-template-base-classes.cpp =================================================================== --- test/SemaTemplate/ms-lookup-template-base-classes.cpp +++ test/SemaTemplate/ms-lookup-template-base-classes.cpp @@ -303,12 +303,12 @@ } namespace two_types_in_base { -template struct A { typedef T NameFromBase; }; -template struct B { struct NameFromBase { T m; }; }; +template struct A { typedef T NameFromBase; }; // expected-note {{member found by ambiguous name lookup}} +template struct B { struct NameFromBase { T m; }; }; // expected-note {{member found by ambiguous name lookup}} template struct C : A, B { - 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) == 4, ""); +static_assert(sizeof(C) == 4, ""); // expected-note {{in instantiation of template class 'two_types_in_base::C' requested here}} } namespace type_and_decl_in_base { @@ -386,9 +386,28 @@ struct A { typedef int NameFromBase; }; template struct B : A {}; -// FIXME: MSVC accepts this. template -struct C : B { NameFromBase m; }; // expected-error {{unknown type name 'NameFromBase'}} +struct C : B { 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 +struct A { typedef T NameFromBase; }; +template +struct B : virtual A {}; +template +struct C : B, virtual A { NameFromBase m; }; // expected-warning {{use of identifier 'NameFromBase' found via unqualified lookup into dependent bases of class templates is a Microsoft extension}} +C c; +} + +namespace type_in_base_of_multiple_dependent_bases { +template +struct A { typedef T NameFromBase; }; +template +struct B : public A {}; +template +struct C : B, public A { 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' is inaccessible due to ambiguity:}} +C c; // expected-note {{in instantiation of template class 'type_in_base_of_multiple_dependent_bases::C' requested here}} } namespace lookup_in_function_contexts {