Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -1495,12 +1495,11 @@ IdentifierInfo **CorrectedII = nullptr); TypeSpecifierType isTagName(IdentifierInfo &II, Scope *S); bool isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S); - void DiagnoseUnknownTypeName(IdentifierInfo *&II, - SourceLocation IILoc, - Scope *S, - CXXScopeSpec *SS, + void DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, + Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, - bool AllowClassTemplates = false); + bool AllowClassTemplates = false, + bool AllowInvalid = false); /// \brief For compatibility with MSVC, we delay parsing of some default /// template type arguments until instantiation time. Emits a warning and Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -2995,6 +2995,27 @@ TypeRep = Actions.ActOnDelayedDefaultTemplateArg( *Tok.getIdentifierInfo(), Tok.getLocation()); } + if (!TypeRep && DSContext == DSC_type_specifier && + Actions.CurContext->isDependentContext() && + getLangOpts().MSVCCompat) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + Actions.DiagnoseUnknownTypeName(II, Tok.getLocation(), getCurScope(), + nullptr, TypeRep, true); + if (TypeRep) { + // The action has suggested that the type TypeRep could be used. + // Set that as the type in the declaration specifiers, + // consume the would-be type name token, and we're done. + const char *PrevSpec; + unsigned DiagID; + DS.SetTypeSpecType(DeclSpec::TST_typename, Tok.getLocation(), + PrevSpec, DiagID, TypeRep, + Actions.getASTContext().getPrintingPolicy()); + DS.SetRangeEnd(Tok.getLocation()); + ConsumeToken(); + // There may be other declaration specifiers after this. + continue; + } + } // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -207,9 +207,15 @@ if (RD && RD->getDescribedClassTemplate()) FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD); } - if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType) - return nullptr; - + if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType) { + ParsedType Result = nullptr; + if (S.getLangOpts().MSVCCompat && S.CurContext->isDependentContext()) { + auto *II2 = const_cast(&II); + S.DiagnoseUnknownTypeName(II2, NameLoc, S.getCurScope(), nullptr, Result, + false, true); + } + return Result; + } // 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. @@ -553,12 +559,11 @@ return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } -void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, - SourceLocation IILoc, - Scope *S, - CXXScopeSpec *SS, +void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, SourceLocation IILoc, + Scope *S, CXXScopeSpec *SS, ParsedType &SuggestedType, - bool AllowClassTemplates) { + bool AllowClassTemplates, + bool AllowInvalid) { // We don't have anything to suggest (yet). SuggestedType = nullptr; @@ -567,7 +572,7 @@ if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc), LookupOrdinaryName, S, SS, llvm::make_unique( - false, false, AllowClassTemplates), + AllowInvalid, false, AllowClassTemplates), CTK_ErrorRecovery)) { if (Corrected.isKeyword()) { // We corrected to a keyword. @@ -576,8 +581,9 @@ } else { // We found a similarly-named type or interface; suggest that. if (!SS || !SS->isSet()) { - diagnoseTypo(Corrected, - PDiag(diag::err_unknown_typename_suggest) << II); + if (!AllowInvalid) + diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) + << II); } else if (DeclContext *DC = computeDeclContext(*SS, false)) { std::string CorrectedStr(Corrected.getAsString(getLangOpts())); bool DroppedSpecifier = Corrected.WillReplaceSpecifier() && @@ -624,10 +630,11 @@ // FIXME: Should we move the logic that tries to recover from a missing tag // (struct, union, enum) from Parser::ParseImplicitInt here, instead? - - if (!SS || (!SS->isSet() && !SS->isInvalid())) - Diag(IILoc, diag::err_unknown_typename) << II; - else if (DeclContext *DC = computeDeclContext(*SS, false)) + + if (!SS || (!SS->isSet() && !SS->isInvalid())) { + if (!AllowInvalid) + Diag(IILoc, diag::err_unknown_typename) << II; + } else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_typename_nested_not_found) << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { Index: lib/Sema/SemaLookup.cpp =================================================================== --- lib/Sema/SemaLookup.cpp +++ lib/Sema/SemaLookup.cpp @@ -4437,13 +4437,6 @@ DisableTypoCorrection) return nullptr; - // In Microsoft mode, don't perform typo correction in a template member - // function dependent context because it interferes with the "lookup into - // dependent bases of class templates" feature. - if (getLangOpts().MSVCCompat && CurContext->isDependentContext() && - isa(CurContext)) - return nullptr; - // We only attempt to correct typos for identifiers. IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!Typo) Index: test/Sema/dtp-lookup-in-base-classes.cpp =================================================================== --- test/Sema/dtp-lookup-in-base-classes.cpp +++ test/Sema/dtp-lookup-in-base-classes.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 %s -fms-compatibility -triple=i386-pc-win32 -verify +// expected-no-diagnostics + +class CCommandBarCtrlBase { +public: + typedef int CMsgHookMap; +}; + +template +class CCommandBarCtrlImpl : public T { + public: + CMsgHookMap zzzz; + void foo(CMsgHookMap hook) { + void *pppp = new CMsgHookMap; + CMsgHookMap xxx = 6666; + zzzz = 7777; + } +}; + +void bar() { + CCommandBarCtrlImpl x; + x.foo(12345); +} +