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];
}
|