Index: cfe/trunk/lib/Sema/SemaTemplate.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp +++ cfe/trunk/lib/Sema/SemaTemplate.cpp @@ -6403,11 +6403,11 @@ // it will be a static member function until we know which template it // specializes), so adjust it now assuming it specializes this template. QualType FT = FD->getType(); + const FunctionProtoType *FPT = FT->castAs(); + FunctionDecl *TmplFD = FunTmpl->getTemplatedDecl(); if (FD->isConstexpr()) { - CXXMethodDecl *OldMD = - dyn_cast(FunTmpl->getTemplatedDecl()); + CXXMethodDecl *OldMD = dyn_cast(TmplFD); if (OldMD && OldMD->isConst()) { - const FunctionProtoType *FPT = FT->castAs(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.TypeQuals |= Qualifiers::Const; FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), @@ -6415,6 +6415,16 @@ } } + // Ignore differences in calling convention until decl merging. + const FunctionProtoType *TmplFT = + TmplFD->getType()->castAs(); + if (FPT->getCallConv() != TmplFT->getCallConv()) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = EPI.ExtInfo.withCallingConv(TmplFT->getCallConv()); + FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(), + EPI); + } + // C++ [temp.expl.spec]p11: // A trailing template-argument can be left unspecified in the // template-id naming an explicit function template specialization Index: cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp =================================================================== --- cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp +++ cfe/trunk/test/SemaCXX/decl-microsoft-call-conv.cpp @@ -144,3 +144,19 @@ // expected-error@+2 {{stdcall and cdecl attributes are not compatible}} // expected-error@+1 {{fastcall and cdecl attributes are not compatible}} void __cdecl __cdecl __stdcall __cdecl __fastcall multi_cc(int x); + +template void __stdcall StdcallTemplate(T) {} +template <> void StdcallTemplate(int) {} +template <> void __stdcall StdcallTemplate(short) {} + +// FIXME: Note the template, not the implicit instantiation. +// expected-error@+2 {{function declared 'cdecl' here was previously declared 'stdcall}} +// expected-note@+1 {{previous declaration is here}} +template <> void __cdecl StdcallTemplate(long) {} + +struct ExactlyInt { + template static int cast_to_int(T) { + return T::this_is_not_an_int(); + } +}; +template <> inline int ExactlyInt::cast_to_int(int x) { return x; }