From: Reid Kleckner Date: Tue, 10 Sep 2013 01:04:45 +0000 (+0000) Subject: Ignore calling conventions when checking function template specializations X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=35bc0055408131d34543c6b4a137d021b26f2d6a;p=clang Ignore calling conventions when checking function template specializations Summary: Calling conventions are inherited during decl merging. Before this change, deduction would fail due to a type mismatch between the template and the specialization. This change adjusts the CCs to match before deduction, and lets the decl merging logic diagnose mismatch or inherit the CC from the template. This allows specializations of static member function templates in the Microsoft C++ ABI. Reviewers: rsmith CC: cfe-commits Differential Revision: http://llvm-reviews.chandlerc.com/D1570 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@190377 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 015d9d8ce9..b6313307c4 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -6403,11 +6403,11 @@ bool Sema::CheckFunctionTemplateSpecialization( // 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 @@ bool Sema::CheckFunctionTemplateSpecialization( } } + // 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 diff --git a/test/SemaCXX/decl-microsoft-call-conv.cpp b/test/SemaCXX/decl-microsoft-call-conv.cpp index 7fcf515d67..b6f7b2d4ab 100644 --- a/test/SemaCXX/decl-microsoft-call-conv.cpp +++ b/test/SemaCXX/decl-microsoft-call-conv.cpp @@ -144,3 +144,19 @@ void multi_attribute(int x) { __builtin_unreachable(); } // 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; }