ms-square-bracket-attributes.mm
7.17 KB
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
// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify -fms-extensions %s -Wno-deprecated-declarations
typedef struct _GUID {
unsigned long Data1;
unsigned short Data2;
unsigned short Data3;
unsigned char Data4[8];
} GUID;
namespace {
// cl.exe supports [] attributes on decls like so:
[uuid( "000000A0-0000-0000-C000-000000000049" )] struct struct_with_uuid;
// Optionally, the uuid can be surrounded by one set of braces.
[uuid(
"{000000A0-0000-0000-C000-000000000049}"
)] struct struct_with_uuid_brace;
// uuids must be ascii string literals.
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid(u8"000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid_u8;
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid(L"000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid_L;
// cl.exe doesn't allow raw string literals in []-style attributes, but does
// allow it for __declspec(uuid()) (u8 literals etc are not allowed there
// either). Since raw string literals not being allowed seems like an
// implementation artifact in cl and not allowing them makes the parse code
// a bit unnatural, do allow this.
[uuid(R"(000000A0-0000-0000-C000-000000000049)")] struct struct_with_uuid_raw;
// Likewise, cl supports UCNs in declspec uuid, but not in []-style uuid.
// clang-cl allows them in both.
[uuid("000000A0-0000\u002D0000-C000-000000000049")] struct struct_with_uuid_ucn;
// cl doesn't allow string concatenation in []-style attributes, for no good
// reason. clang-cl allows them.
[uuid("000000A0-00" "00-0000-C000-000000000049")] struct struct_with_uuid_split;
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
[uuid("{000000A0-0000-0000-C000-000000000049}", "1")] struct S {};
// expected-error@+1 {{expected '('}}
[uuid{"000000A0-0000-0000-C000-000000000049"}] struct T {};
// expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}}
[uuid("000000A0-0000-0000-C000-000000000049"}] struct U {};
// In addition to uuids in string literals, cl also allows uuids that are not
// in a string literal, only delimited by (). The contents of () are almost
// treated like a literal (spaces there aren't ignored), but macro substitution,
// \ newline escapes, and so on are performed.
[ uuid (000000A0-0000-0000-C000-000000000049) ] struct struct_with_uuid2;
[uuid({000000A0-0000-0000-C000-000000000049})] struct struct_with_uuid2_brace;
// The non-quoted form doesn't allow any whitespace inside the parens:
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid( 000000A0-0000-0000-C000-000000000049)] struct struct_with_uuid2;
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid(000000A0-0000 -0000-C000-000000000049)] struct struct_with_uuid2;
// expected-error@+2 {{uuid attribute contains a malformed GUID}}
[uuid(000000A0-0000
-0000-C000-000000000049)] struct struct_with_uuid2;
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid(000000A0-0000/**/-0000-C000-000000000049)] struct struct_with_uuid2;
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid(000000A0-0000-0000-C000-000000000049 )] struct struct_with_uuid2;
// expected-error@+2 {{uuid attribute contains a malformed GUID}}
[uuid(000000A0-0000-0000-C000-000000000049
)
] struct struct_with_uuid2;
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid({000000A0-0000-""0000-C000-000000000049})] struct struct_with_uuid2;
// Line continuations and macro substitution are fine though:
[uuid(000000A0-0000-0000-\
C000-000000000049)] struct struct_with_uuid2_cont;
#define UUID 000000A0-0000-0000-C000-000000000049
#define UUID_PART 000000A0-0000
[uuid(UUID)] struct struct_with_uuid2_macro;
[uuid(UUID_PART-0000-C000-000000000049)] struct struct_with_uuid2_macro_part;
// Both cl and clang-cl accept trigraphs here (with /Zc:trigraphs, off by
// default)
// expected-warning@+1 2{{trigraph converted}}
[uuid(??<000000A0-0000-0000-C000-000000000049??>)]
struct struct_with_uuid2_trigraph;
// UCNs cannot be used in this form because they're prohibited by C99.
// expected-error@+1 {{character '-' cannot be specified by a universal character name}}
[uuid(000000A0-0000\u002D0000-C000-000000000049)] struct struct_with_uuid2_ucn;
// Invalid digits.
// expected-error@+1 {{uuid attribute contains a malformed GUID}}
[uuid(0Z0000A0-0000-0000-C000-000000000049)] struct struct_with_uuid2;
struct OuterClass {
// [] uuids and inner classes are weird in cl.exe: It warns that uuid on
// nested types has undefined behavior, and errors out __uuidof() claiming
// that the inner type has no assigned uuid. Things work fine if __declspec()
// is used instead. clang-cl handles this fine.
[uuid(10000000-0000-0000-0000-000000000000)] class InnerClass1;
[uuid(10000000-0000-0000-0000-000000000000)] class InnerClass2 {} ic;
[uuid(10000000-0000-0000-0000-000000000000)] static class InnerClass3 {} sic;
// Putting `static` in front of [...] causes parse errors in both cl and clang
// This is the only syntax to declare an inner class with []-style attributes
// that works in cl: Declare the inner class without an attribute, and then
// have the []-style attribute on the definition.
class InnerClass;
};
[uuid(10000000-0000-0000-0000-000000000000)] class OuterClass::InnerClass {};
void use_it() {
(void)__uuidof(struct_with_uuid);
(void)__uuidof(struct_with_uuid_brace);
(void)__uuidof(struct_with_uuid_raw);
(void)__uuidof(struct_with_uuid_ucn);
(void)__uuidof(struct_with_uuid_split);
(void)__uuidof(struct_with_uuid2);
(void)__uuidof(struct_with_uuid2_brace);
(void)__uuidof(struct_with_uuid2_cont);
(void)__uuidof(struct_with_uuid2_macro);
(void)__uuidof(struct_with_uuid2_macro_part);
(void)__uuidof(struct_with_uuid2_trigraph);
(void)__uuidof(OuterClass::InnerClass);
(void)__uuidof(OuterClass::InnerClass1);
(void)__uuidof(OuterClass::InnerClass2);
(void)__uuidof(OuterClass::InnerClass3);
(void)__uuidof(OuterClass().ic);
(void)__uuidof(OuterClass::sic);
}
// expected-warning@+1 {{'uuid' attribute only applies to structs, unions, classes, and enums}}
[uuid("000000A0-0000-0000-C000-000000000049")] void f();
}
// clang supports these on toplevel decls, but not on local decls since this
// syntax is ambiguous with lambdas and Objective-C message send expressions.
// This file documents clang's shortcomings and lists a few constructs that
// one has to keep in mind when trying to fix this. System headers only seem
// to use these attributes on toplevel decls, so supporting this is not very
// important.
void local_class() {
// FIXME: MSVC accepts, but we reject due to ambiguity.
// expected-error@+1 {{expected body of lambda expression}}
[uuid("a5a7bd07-3b14-49bc-9399-de066d4d72cd")] struct Local {
int x;
};
}
void useit(int);
int lambda() {
int uuid = 42;
[uuid]() { useit(uuid); }();
// C++14 lambda init captures:
[uuid(00000000-0000-0000-0000-000000000000)] { return uuid; }();
[uuid("00000000-0000-0000-0000-000000000000")](int n) { return uuid[n]; }(3);
}
@interface NSObject
- (void)retain;
@end
int message_send(id uuid) {
[uuid retain];
}
NSObject* uuid(const char*);
int message_send2() {
[uuid("a5a7bd07-3b14-49bc-9399-de066d4d72cd") retain];
}