| 1 | // RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify -fms-extensions %s -Wno-deprecated-declarations |
| 2 | |
| 3 | typedef struct _GUID { |
| 4 | unsigned long Data1; |
| 5 | unsigned short Data2; |
| 6 | unsigned short Data3; |
| 7 | unsigned char Data4[8]; |
| 8 | } GUID; |
| 9 | |
| 10 | namespace { |
| 11 | // cl.exe supports [] attributes on decls like so: |
| 12 | [uuid( "000000A0-0000-0000-C000-000000000049" )] struct struct_with_uuid; |
| 13 | |
| 14 | // Optionally, the uuid can be surrounded by one set of braces. |
| 15 | [uuid( |
| 16 | "{000000A0-0000-0000-C000-000000000049}" |
| 17 | )] struct struct_with_uuid_brace; |
| 18 | |
| 19 | // uuids must be ascii string literals. |
| 20 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 21 | [uuid(u8"000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid_u8; |
| 22 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 23 | [uuid(L"000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid_L; |
| 24 | |
| 25 | // cl.exe doesn't allow raw string literals in []-style attributes, but does |
| 26 | // allow it for __declspec(uuid()) (u8 literals etc are not allowed there |
| 27 | // either). Since raw string literals not being allowed seems like an |
| 28 | // implementation artifact in cl and not allowing them makes the parse code |
| 29 | // a bit unnatural, do allow this. |
| 30 | [uuid(R"(000000A0-0000-0000-C000-000000000049)")] struct struct_with_uuid_raw; |
| 31 | |
| 32 | // Likewise, cl supports UCNs in declspec uuid, but not in []-style uuid. |
| 33 | // clang-cl allows them in both. |
| 34 | [uuid("000000A0-0000\u002D0000-C000-000000000049")] struct struct_with_uuid_ucn; |
| 35 | |
| 36 | // cl doesn't allow string concatenation in []-style attributes, for no good |
| 37 | // reason. clang-cl allows them. |
| 38 | [uuid("000000A0-00" "00-0000-C000-000000000049")] struct struct_with_uuid_split; |
| 39 | |
| 40 | // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} |
| 41 | [uuid("{000000A0-0000-0000-C000-000000000049}", "1")] struct S {}; |
| 42 | // expected-error@+1 {{expected '('}} |
| 43 | [uuid{"000000A0-0000-0000-C000-000000000049"}] struct T {}; |
| 44 | // expected-error@+1 {{expected ')'}} expected-note@+1 {{to match this '('}} |
| 45 | [uuid("000000A0-0000-0000-C000-000000000049"}] struct U {}; |
| 46 | |
| 47 | |
| 48 | // In addition to uuids in string literals, cl also allows uuids that are not |
| 49 | // in a string literal, only delimited by (). The contents of () are almost |
| 50 | // treated like a literal (spaces there aren't ignored), but macro substitution, |
| 51 | // \ newline escapes, and so on are performed. |
| 52 | |
| 53 | [ uuid (000000A0-0000-0000-C000-000000000049) ] struct struct_with_uuid2; |
| 54 | [uuid({000000A0-0000-0000-C000-000000000049})] struct struct_with_uuid2_brace; |
| 55 | |
| 56 | // The non-quoted form doesn't allow any whitespace inside the parens: |
| 57 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 58 | [uuid( 000000A0-0000-0000-C000-000000000049)] struct struct_with_uuid2; |
| 59 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 60 | [uuid(000000A0-0000 -0000-C000-000000000049)] struct struct_with_uuid2; |
| 61 | // expected-error@+2 {{uuid attribute contains a malformed GUID}} |
| 62 | [uuid(000000A0-0000 |
| 63 | -0000-C000-000000000049)] struct struct_with_uuid2; |
| 64 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 65 | [uuid(000000A0-0000/**/-0000-C000-000000000049)] struct struct_with_uuid2; |
| 66 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 67 | [uuid(000000A0-0000-0000-C000-000000000049 )] struct struct_with_uuid2; |
| 68 | // expected-error@+2 {{uuid attribute contains a malformed GUID}} |
| 69 | [uuid(000000A0-0000-0000-C000-000000000049 |
| 70 | ) |
| 71 | ] struct struct_with_uuid2; |
| 72 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 73 | [uuid({000000A0-0000-""0000-C000-000000000049})] struct struct_with_uuid2; |
| 74 | |
| 75 | // Line continuations and macro substitution are fine though: |
| 76 | [uuid(000000A0-0000-0000-\ |
| 77 | C000-000000000049)] struct struct_with_uuid2_cont; |
| 78 | #define UUID 000000A0-0000-0000-C000-000000000049 |
| 79 | #define UUID_PART 000000A0-0000 |
| 80 | [uuid(UUID)] struct struct_with_uuid2_macro; |
| 81 | [uuid(UUID_PART-0000-C000-000000000049)] struct struct_with_uuid2_macro_part; |
| 82 | |
| 83 | // Both cl and clang-cl accept trigraphs here (with /Zc:trigraphs, off by |
| 84 | // default) |
| 85 | // expected-warning@+1 2{{trigraph converted}} |
| 86 | [uuid(??<000000A0-0000-0000-C000-000000000049??>)] |
| 87 | struct struct_with_uuid2_trigraph; |
| 88 | |
| 89 | // UCNs cannot be used in this form because they're prohibited by C99. |
| 90 | // expected-error@+1 {{character '-' cannot be specified by a universal character name}} |
| 91 | [uuid(000000A0-0000\u002D0000-C000-000000000049)] struct struct_with_uuid2_ucn; |
| 92 | |
| 93 | // Invalid digits. |
| 94 | // expected-error@+1 {{uuid attribute contains a malformed GUID}} |
| 95 | [uuid(0Z0000A0-0000-0000-C000-000000000049)] struct struct_with_uuid2; |
| 96 | |
| 97 | struct OuterClass { |
| 98 | // [] uuids and inner classes are weird in cl.exe: It warns that uuid on |
| 99 | // nested types has undefined behavior, and errors out __uuidof() claiming |
| 100 | // that the inner type has no assigned uuid. Things work fine if __declspec() |
| 101 | // is used instead. clang-cl handles this fine. |
| 102 | [uuid(10000000-0000-0000-0000-000000000000)] class InnerClass1; |
| 103 | [uuid(10000000-0000-0000-0000-000000000000)] class InnerClass2 {} ic; |
| 104 | [uuid(10000000-0000-0000-0000-000000000000)] static class InnerClass3 {} sic; |
| 105 | // Putting `static` in front of [...] causes parse errors in both cl and clang |
| 106 | |
| 107 | // This is the only syntax to declare an inner class with []-style attributes |
| 108 | // that works in cl: Declare the inner class without an attribute, and then |
| 109 | // have the []-style attribute on the definition. |
| 110 | class InnerClass; |
| 111 | }; |
| 112 | [uuid(10000000-0000-0000-0000-000000000000)] class OuterClass::InnerClass {}; |
| 113 | |
| 114 | void use_it() { |
| 115 | (void)__uuidof(struct_with_uuid); |
| 116 | (void)__uuidof(struct_with_uuid_brace); |
| 117 | (void)__uuidof(struct_with_uuid_raw); |
| 118 | (void)__uuidof(struct_with_uuid_ucn); |
| 119 | (void)__uuidof(struct_with_uuid_split); |
| 120 | |
| 121 | (void)__uuidof(struct_with_uuid2); |
| 122 | (void)__uuidof(struct_with_uuid2_brace); |
| 123 | (void)__uuidof(struct_with_uuid2_cont); |
| 124 | (void)__uuidof(struct_with_uuid2_macro); |
| 125 | (void)__uuidof(struct_with_uuid2_macro_part); |
| 126 | (void)__uuidof(struct_with_uuid2_trigraph); |
| 127 | |
| 128 | (void)__uuidof(OuterClass::InnerClass); |
| 129 | (void)__uuidof(OuterClass::InnerClass1); |
| 130 | (void)__uuidof(OuterClass::InnerClass2); |
| 131 | (void)__uuidof(OuterClass::InnerClass3); |
| 132 | (void)__uuidof(OuterClass().ic); |
| 133 | (void)__uuidof(OuterClass::sic); |
| 134 | } |
| 135 | |
| 136 | // expected-warning@+1 {{'uuid' attribute only applies to structs, unions, classes, and enums}} |
| 137 | [uuid("000000A0-0000-0000-C000-000000000049")] void f(); |
| 138 | } |
| 139 | |
| 140 | // clang supports these on toplevel decls, but not on local decls since this |
| 141 | // syntax is ambiguous with lambdas and Objective-C message send expressions. |
| 142 | // This file documents clang's shortcomings and lists a few constructs that |
| 143 | // one has to keep in mind when trying to fix this. System headers only seem |
| 144 | // to use these attributes on toplevel decls, so supporting this is not very |
| 145 | // important. |
| 146 | |
| 147 | void local_class() { |
| 148 | // FIXME: MSVC accepts, but we reject due to ambiguity. |
| 149 | // expected-error@+1 {{expected body of lambda expression}} |
| 150 | [uuid("a5a7bd07-3b14-49bc-9399-de066d4d72cd")] struct Local { |
| 151 | int x; |
| 152 | }; |
| 153 | } |
| 154 | |
| 155 | void useit(int); |
| 156 | int lambda() { |
| 157 | int uuid = 42; |
| 158 | [uuid]() { useit(uuid); }(); |
| 159 | |
| 160 | // C++14 lambda init captures: |
| 161 | [uuid(00000000-0000-0000-0000-000000000000)] { return uuid; }(); |
| 162 | [uuid("00000000-0000-0000-0000-000000000000")](int n) { return uuid[n]; }(3); |
| 163 | } |
| 164 | |
| 165 | @interface NSObject |
| 166 | - (void)retain; |
| 167 | @end |
| 168 | int message_send(id uuid) { |
| 169 | [uuid retain]; |
| 170 | } |
| 171 | NSObject* uuid(const char*); |
| 172 | int message_send2() { |
| 173 | [uuid("a5a7bd07-3b14-49bc-9399-de066d4d72cd") retain]; |
| 174 | } |
| 175 | |