Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8673,9 +8673,12 @@ // member function definition. // MSVC permits the use of a 'static' storage specifier on an out-of-line - // member function template declaration, warn about this. + // member function template declaration and class member template + // declaration (MSVC versions before 2015), warn about this. Diag(D.getDeclSpec().getStorageClassSpecLoc(), - NewFD->getDescribedFunctionTemplate() && getLangOpts().MSVCCompat + ((!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && + cast(DC)->getDescribedClassTemplate()) || + (getLangOpts().MSVCCompat && NewFD->getDescribedFunctionTemplate())) ? diag::ext_static_out_of_line : diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } Index: test/SemaCXX/warn-static-outside-class-definition.cpp =================================================================== --- test/SemaCXX/warn-static-outside-class-definition.cpp +++ test/SemaCXX/warn-static-outside-class-definition.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fms-compatibility -fsyntax-only -verify %s +// RUN: %clang_cc1 -fms-compatibility -fsyntax-only -fms-compatibility-version=12.0 -verify %s struct C { template static int foo(T); @@ -9,3 +10,13 @@ return 0; } +template struct S { + void f(); +}; + +template static void S::f() {} +#if _MSC_VER >= 1900 + //expected-error@-2 {{'static' can only be specified inside the class definition}} +#else + //expected-warning@-4 {{'static' can only be specified inside the class definition}} +#endif