xref: /llvm-project/clang/test/SemaCXX/ms-uuid.cpp (revision 9b718c0d5d0f1f146957753b7785f87f58cccfec)
1 // RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -Wno-deprecated-declarations
2 // RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s -Wno-deprecated-declarations -fexperimental-new-constant-interpreter
3 // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -fms-extensions %s -Wno-deprecated-declarations
4 // RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify -fms-extensions %s -Wno-deprecated-declarations -fexperimental-new-constant-interpreter
5 
6 typedef struct _GUID {
7   __UINT32_TYPE__ Data1;
8   __UINT16_TYPE__ Data2;
9   __UINT16_TYPE__ Data3;
10   __UINT8_TYPE__ Data4[8];
11 } GUID;
12 
13 namespace {
14 // cl.exe's behavior with merging uuid attributes is a bit erratic:
15 // * In []-style attributes, a single [] list must not list a duplicate uuid
16 //   (even if it's the same uuid), and only a single declaration of a class
17 //   must have a uuid else the compiler errors out (even if two declarations of
18 //   a class have the same uuid).
19 // * For __declspec(uuid(...)), it's ok if several declarations of a class have
20 //   an uuid, as long as it's the same uuid each time.  If uuids on declarations
21 //   don't match, the compiler errors out.
22 // * If there are several __declspec(uuid(...))s on one declaration, the
23 //   compiler only warns about this and uses the last uuid.  It even warns if
24 //   the uuids are the same.
25 
26 // clang-cl implements the following simpler (but largely compatible) behavior
27 // instead:
28 // * [] and __declspec uuids have the same behavior.
29 // * If there are several uuids on a class (no matter if on the same decl or
30 //   on several decls), it is an error if they don't match.
31 // * Having several uuids that match is ok.
32 
33 // Both cl and clang-cl accept this:
34 class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1;
35 class __declspec(uuid("000000a0-0000-0000-c000-000000000049")) C1;
36 class __declspec(uuid("{000000a0-0000-0000-C000-000000000049}")) C1;
37 class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1 {};
38 
39 // Both cl and clang-cl error out on this:
40 // expected-note@+1 2{{previous uuid specified here}}
41 class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C2;
42 // expected-error@+1 {{uuid does not match previous declaration}}
43 class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C2;
44 // expected-error@+1 {{uuid does not match previous declaration}}
45 class __declspec(uuid("220000A0-0000-0000-C000-000000000049")) C2 {};
46 
47 // expected-note@+1 {{previous uuid specified here}}
48 class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C2_2;
49 class C2_2;
50 // expected-error@+1 {{uuid does not match previous declaration}}
51 class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C2_2;
52 
53 // clang-cl accepts this, but cl errors out:
54 [uuid("000000A0-0000-0000-C000-000000000049")] class C3;
55 [uuid("000000A0-0000-0000-C000-000000000049")] class C3;
56 [uuid("000000A0-0000-0000-C000-000000000049")] class C3 {};
57 
58 // Both cl and clang-cl error out on this (but for different reasons):
59 // expected-note@+1 2{{previous uuid specified here}}
60 [uuid("000000A0-0000-0000-C000-000000000049")] class C4;
61 // expected-error@+1 {{uuid does not match previous declaration}}
62 [uuid("110000A0-0000-0000-C000-000000000049")] class C4;
63 // expected-error@+1 {{uuid does not match previous declaration}}
64 [uuid("220000A0-0000-0000-C000-000000000049")] class C4 {};
65 
66 // Both cl and clang-cl error out on this:
67 // expected-error@+1 {{uuid does not match previous declaration}}
68 class __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
69 // expected-note@+1 {{previous uuid specified here}}
70       __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C5;
71 
72 // expected-error@+1 {{uuid does not match previous declaration}}
73 [uuid("000000A0-0000-0000-C000-000000000049"),
74 // expected-note@+1 {{previous uuid specified here}}
75  uuid("110000A0-0000-0000-C000-000000000049")] class C6;
76 
77 // cl doesn't diagnose having one uuid each as []-style attributes and as
78 // __declspec, even if the uuids differ.  clang-cl errors if they differ.
79 [uuid("000000A0-0000-0000-C000-000000000049")]
80 class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C7;
81 
82 // expected-note@+1 {{previous uuid specified here}}
83 [uuid("000000A0-0000-0000-C000-000000000049")]
84 // expected-error@+1 {{uuid does not match previous declaration}}
85 class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C8;
86 
87 
88 // cl warns on this, but clang-cl is fine with it (which is consistent with
89 // e.g. specifying __multiple_inheritance several times, which cl accepts
90 // without warning too).
91 class __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
92       __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C9;
93 
94 // cl errors out on this, but clang-cl is fine with it (to be consistent with
95 // the previous case).
96 [uuid("000000A0-0000-0000-C000-000000000049"),
97  uuid("000000A0-0000-0000-C000-000000000049")] class C10;
98 
99 template <const GUID* p>
F1()100 void F1() {
101   // Regression test for PR24986. The given GUID should just work as a pointer.
102   const GUID* q = p;
103 }
104 
F2()105 void F2() {
106   // The UUID should work for a non-type template parameter.
107   F1<&__uuidof(C1)>();
108 }
109 
110 }
111 
112 // Test class/struct redeclaration where the subsequent
113 // declaration has a uuid attribute
114 struct X{};
115 
116 struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) X;
117 
118 namespace ConstantEvaluation {
119   class __declspec(uuid("1babb1ed-feed-c01d-1ced-decafc0ffee5")) Request;
120   constexpr GUID a = __uuidof(Request);
121   static_assert(a.Data1 == 0x1babb1ed, "");
122   static_assert(__uuidof(Request).Data1 == 0x1babb1ed, "");
123   static_assert(a.Data2 == 0xfeed, "");
124   static_assert(__uuidof(Request).Data2 == 0xfeed, "");
125   static_assert(a.Data3 == 0xc01d, "");
126   static_assert(__uuidof(Request).Data3 == 0xc01d, "");
127   static_assert(a.Data4[0] == 0x1c, "");
128   static_assert(__uuidof(Request).Data4[0] == 0x1c, "");
129   static_assert(a.Data4[1] == 0xed, "");
130   static_assert(__uuidof(Request).Data4[1] == 0xed, "");
131   static_assert(a.Data4[2] == 0xde, "");
132   static_assert(__uuidof(Request).Data4[2] == 0xde, "");
133   static_assert(a.Data4[7] == 0xe5, "");
134   static_assert(__uuidof(Request).Data4[7] == 0xe5, "");
135   constexpr int k = __uuidof(Request).Data4[8]; // expected-error {{constant expression}} expected-note {{past-the-end}}
136 }
137