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,10 @@ return 0; } +template struct S { + void f(); +}; + +template static void S::f() { + //expected-warning@-1 {{'static' can only be specified inside the class definition}} +}