// 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<FunctionProtoType>();
+ FunctionDecl *TmplFD = FunTmpl->getTemplatedDecl();
if (FD->isConstexpr()) {
- CXXMethodDecl *OldMD =
- dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+ CXXMethodDecl *OldMD = dyn_cast<CXXMethodDecl>(TmplFD);
if (OldMD && OldMD->isConst()) {
- const FunctionProtoType *FPT = FT->castAs<FunctionProtoType>();
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
EPI.TypeQuals |= Qualifiers::Const;
FT = Context.getFunctionType(FPT->getResultType(), FPT->getArgTypes(),
}
}
+ // Ignore differences in calling convention until decl merging.
+ const FunctionProtoType *TmplFT =
+ TmplFD->getType()->castAs<FunctionProtoType>();
+ 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
// 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 <typename T> void __stdcall StdcallTemplate(T) {}
+template <> void StdcallTemplate<int>(int) {}
+template <> void __stdcall StdcallTemplate<short>(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>(long) {}
+
+struct ExactlyInt {
+ template <typename T> static int cast_to_int(T) {
+ return T::this_is_not_an_int();
+ }
+};
+template <> inline int ExactlyInt::cast_to_int<int>(int x) { return x; }