aboutsummaryrefslogtreecommitdiff
path: root/test/SemaCXX/decl-microsoft-call-conv.cpp
blob: 9f1463245ba29c89b673a5cbd7df0104150e0874 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
// RUN: %clang_cc1 -triple i686-pc-win32 -cxx-abi microsoft -fms-extensions -verify %s

typedef void void_fun_t();
typedef void __cdecl cdecl_fun_t();

// Pointers to free functions
void            free_func_default(); // expected-note 2 {{previous declaration is here}}
void __cdecl    free_func_cdecl(); // expected-note 2 {{previous declaration is here}}
void __stdcall  free_func_stdcall(); // expected-note 2 {{previous declaration is here}}
void __fastcall free_func_fastcall(); // expected-note 2 {{previous declaration is here}}

void __cdecl    free_func_default();
void __stdcall  free_func_default(); // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void __fastcall free_func_default(); // expected-error {{function declared 'fastcall' here was previously declared without calling convention}}

void            free_func_cdecl();
void __stdcall  free_func_cdecl(); // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}
void __fastcall free_func_cdecl(); // expected-error {{function declared 'fastcall' here was previously declared 'cdecl'}}

void            free_func_stdcall();
void __cdecl    free_func_stdcall(); // expected-error {{function declared 'cdecl' here was previously declared 'stdcall'}}
void __fastcall free_func_stdcall(); // expected-error {{function declared 'fastcall' here was previously declared 'stdcall'}}

void __cdecl    free_func_fastcall(); // expected-error {{function declared 'cdecl' here was previously declared 'fastcall'}}
void __stdcall  free_func_fastcall(); // expected-error {{function declared 'stdcall' here was previously declared 'fastcall'}}
void            free_func_fastcall();

// Overloaded functions may have different calling conventions
void __fastcall free_func_default(int);
void __cdecl    free_func_default(int *);

void __thiscall free_func_cdecl(char *);
void __cdecl    free_func_cdecl(double);

typedef void void_fun_t();
typedef void __cdecl cdecl_fun_t();

// Pointers to member functions
struct S {
  void            member_default1(); // expected-note {{previous declaration is here}}
  void            member_default2();
  void __cdecl    member_cdecl1();
  void __cdecl    member_cdecl2(); // expected-note {{previous declaration is here}}
  void __thiscall member_thiscall1();
  void __thiscall member_thiscall2(); // expected-note {{previous declaration is here}}

  // Typedefs carrying the __cdecl convention are adjusted to __thiscall.
  void_fun_t           member_typedef_default; // expected-note {{previous declaration is here}}
  cdecl_fun_t          member_typedef_cdecl1;  // expected-note {{previous declaration is here}}
  cdecl_fun_t __cdecl  member_typedef_cdecl2;
  void_fun_t __stdcall member_typedef_stdcall;

  // Static member functions can't be __thiscall
  static void            static_member_default1();
  static void            static_member_default2();
  static void            static_member_default3(); // expected-note {{previous declaration is here}}
  static void __cdecl    static_member_cdecl1();
  static void __cdecl    static_member_cdecl2(); // expected-note {{previous declaration is here}}
  static void __stdcall  static_member_stdcall1();
  static void __stdcall  static_member_stdcall2();

  // Variadic functions can't be other than default or __cdecl
  void            member_variadic_default(int x, ...);
  void __cdecl    member_variadic_cdecl(int x, ...);

  static void            static_member_variadic_default(int x, ...);
  static void __cdecl    static_member_variadic_cdecl(int x, ...);
};

void __cdecl    S::member_default1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __thiscall S::member_default2() {}

void __cdecl   S::member_typedef_default() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __cdecl   S::member_typedef_cdecl1() {} // expected-error {{function declared 'cdecl' here was previously declared without calling convention}}
void __cdecl   S::member_typedef_cdecl2() {}
void __stdcall S::member_typedef_stdcall() {}

void            S::member_cdecl1() {}
void __thiscall S::member_cdecl2() {} // expected-error {{function declared 'thiscall' here was previously declared 'cdecl'}}

void            S::member_thiscall1() {}
void __cdecl    S::member_thiscall2() {} // expected-error {{function declared 'cdecl' here was previously declared 'thiscall'}}

void            S::static_member_default1() {}
void __cdecl    S::static_member_default2() {}
void __stdcall  S::static_member_default3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}

void            S::static_member_cdecl1() {}
void __stdcall  S::static_member_cdecl2() {} // expected-error {{function declared 'stdcall' here was previously declared 'cdecl'}}

void __cdecl    S::member_variadic_default(int x, ...) { (void)x; }
void            S::member_variadic_cdecl(int x, ...) { (void)x; }

void __cdecl    S::static_member_variadic_default(int x, ...) { (void)x; }
void            S::static_member_variadic_cdecl(int x, ...) { (void)x; }

// Declare a template using a calling convention.
template <class CharT> inline int __cdecl mystrlen(const CharT *str) {
  int i;
  for (i = 0; str[i]; i++) { }
  return i;
}
extern int sse_strlen(const char *str);
template <> inline int __cdecl mystrlen(const char *str) {
  return sse_strlen(str);
}
void use_tmpl(const char *str, const int *ints) {
  mystrlen(str);
  mystrlen(ints);
}

struct MixedCCStaticOverload {
  static void overloaded(int a);
  static void __stdcall overloaded(short a);
};

void MixedCCStaticOverload::overloaded(int a) {}
void MixedCCStaticOverload::overloaded(short a) {}

// Friend function decls are cdecl by default, not thiscall.  Friend method
// decls should always be redeclarations, because the class cannot be
// incomplete.
struct FriendClass {
  void friend_method() {}
};
void __stdcall friend_stdcall1() {}
class MakeFriendDecls {
  int x;
  friend void FriendClass::friend_method();
  friend void              friend_default();
  friend void              friend_stdcall1();
  friend void __stdcall    friend_stdcall2();
  friend void              friend_stdcall3(); // expected-note {{previous declaration is here}}
};
void           friend_default() {}
void __stdcall friend_stdcall3() {} // expected-error {{function declared 'stdcall' here was previously declared without calling convention}}
void __stdcall friend_stdcall2() {}

// Test functions with multiple attributes.
void __attribute__((noreturn)) __stdcall __attribute__((regparm(1))) multi_attribute(int x);
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 <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; }

namespace test2 {
  class foo {
    template <typename T> void bar(T v);
  };
  extern template void foo::bar(const void *);
}

namespace test3 {
  struct foo {
    typedef void bar();
  };
  bool zed(foo::bar *);
  void bah() {}
  void baz() { zed(bah); }
}

namespace test4 {
  class foo {
    template <typename T> static void bar(T v);
  };
  extern template void foo::bar(const void *);
}

namespace test5 {
  template <class T>
  class valarray {
    void bar();
  };
  extern template void valarray<int>::bar();
}