reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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]; 
}