Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -128,6 +128,51 @@ return false; } +static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, + CXXRecordDecl *RD, + const IdentifierInfo &II, + SourceLocation NameLoc) { + // 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) + continue; + auto *TD = TST->getTemplateName().getAsTemplateDecl(); + if (!TD) + continue; + auto *BasePrimaryTemplate = cast(TD->getTemplatedDecl()); + for (NamedDecl *ND : BasePrimaryTemplate->lookup(&II)) { + if (FoundTypeDecl) + return ParsedType(); + FoundTypeDecl = isa(ND); + if (!FoundTypeDecl) + return ParsedType(); + } + } + + // We found some types in dependent base classes. Recover as if the user + // wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the + // lookup during template instantiation. + S.Diag(NameLoc, diag::ext_found_via_dependent_bases_lookup) << &II; + + ASTContext &Context = S.Context; + auto *NNS = NestedNameSpecifier::Create(Context, nullptr, false, + cast(Context.getRecordType(RD))); + QualType T = Context.getDependentNameType(ETK_Typename, NNS, &II); + + CXXScopeSpec SS; + SS.MakeTrivial(Context, NNS, SourceRange(NameLoc)); + + TypeLocBuilder Builder; + DependentNameTypeLoc DepTL = Builder.push(T); + DepTL.setNameLoc(NameLoc); + DepTL.setElaboratedKeywordLoc(SourceLocation()); + DepTL.setQualifierLoc(SS.getWithLocInContext(Context)); + return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); +} + /// \brief If the identifier refers to a type name within this scope, /// return the declaration of that type. /// @@ -209,6 +254,18 @@ } else { // Perform unqualified name lookup. LookupName(Result, S); + + // For unqualified lookup in a class template in MSVC mode, look into + // dependent base classes where the primary class template is known. + if (Result.empty() && getLangOpts().MSVCCompat && (!SS || SS->isEmpty())) { + auto *RD = dyn_cast(CurContext); + if (RD && RD->getDescribedClassTemplate()) { + ParsedType TypeInBase = + recoverFromTypeInKnownDependentBase(*this, RD, II, NameLoc); + if (TypeInBase) + return TypeInBase; + } + } } NamedDecl *IIDecl = nullptr; 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 @@ -275,3 +275,59 @@ }; template struct Derived; } + +namespace typedef_in_base { +template struct A { typedef T NameFromBase; }; +template struct B : A { + NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}} +}; +static_assert(sizeof(B) == 4, ""); +} + +namespace struct_in_base { +template struct A { struct NameFromBase {}; }; +template struct B : A { + NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}} +}; +static_assert(sizeof(B) == 1, ""); +} + +namespace enum_in_base { +template struct A { enum NameFromBase { X }; }; +template struct B : A { + NameFromBase m; // expected-warning {{found via unqualified lookup into dependent bases}} +}; +static_assert(sizeof(B) == sizeof(A::NameFromBase), ""); +} + +namespace two_types_in_base { +template struct A { typedef T NameFromBase; }; +template struct B { struct NameFromBase { T m; }; }; +template struct C : A, B { + NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} +}; +static_assert(sizeof(C) == 4, ""); +} + +namespace type_and_decl_in_base { +template struct A { typedef T NameFromBase; }; +template struct B { static const T NameFromBase = 42; }; +template struct C : A, B { + NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} +}; +} + +namespace template_in_base { +template struct A { + template struct NameFromBase { U x; }; +}; +template struct B : A { + // Correct form. + typename B::template NameFromBase m; +}; +template struct C : A { + // Incorrect form. + NameFromBase m; // expected-error {{unknown type name 'NameFromBase'}} + //expected-error@-1 {{expected member name or ';' after declaration specifiers}} +}; +}