class GNU<string name> : Spelling<name, "GNU">;
class Declspec<string name> : Spelling<name, "Declspec">;
+class Microsoft<string name> : Spelling<name, "Microsoft">;
class CXX11<string namespace, string name, int version = 1>
: Spelling<name, "CXX11"> {
string Namespace = namespace;
}
def Uuid : InheritableAttr {
- let Spellings = [Declspec<"uuid">];
+ let Spellings = [Declspec<"uuid">, Microsoft<"uuid">];
let Args = [StringArgument<"Guid">];
// let Subjects = SubjectList<[CXXRecord]>;
let LangOpts = [MicrosoftExt, Borland];
if (getLangOpts().MicrosoftExt && Tok.is(tok::l_square))
ParseMicrosoftAttributes(attrs, endLoc);
}
+ void ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs);
void ParseMicrosoftAttributes(ParsedAttributes &attrs,
SourceLocation *endLoc = nullptr);
void MaybeParseMicrosoftDeclSpecs(ParsedAttributes &Attrs,
return EndLoc;
}
+/// Parse uuid() attribute when it appears in a [] Microsoft attribute.
+void Parser::ParseMicrosoftUuidAttributeArgs(ParsedAttributes &Attrs) {
+ assert(Tok.is(tok::identifier) && "Not a Microsoft attribute list");
+ IdentifierInfo *UuidIdent = Tok.getIdentifierInfo();
+ assert(UuidIdent->getName() == "uuid" && "Not a Microsoft attribute list");
+
+ SourceLocation UuidLoc = Tok.getLocation();
+ ConsumeToken();
+
+ // Ignore the left paren location for now.
+ BalancedDelimiterTracker T(*this, tok::l_paren);
+ if (T.consumeOpen()) {
+ Diag(Tok, diag::err_expected) << tok::l_paren;
+ return;
+ }
+
+ ArgsVector ArgExprs;
+ if (Tok.is(tok::string_literal)) {
+ // Easy case: uuid("...") -- quoted string.
+ ExprResult StringResult = ParseStringLiteralExpression();
+ if (StringResult.isInvalid())
+ return;
+ ArgExprs.push_back(StringResult.get());
+ } else {
+ // something like uuid({000000A0-0000-0000-C000-000000000049}) -- no
+ // quotes in the parens. Just append the spelling of all tokens encountered
+ // until the closing paren.
+
+ SmallString<42> StrBuffer; // 2 "", 36 bytes UUID, 2 optional {}, 1 nul
+ StrBuffer += "\"";
+
+ // Since none of C++'s keywords match [a-f]+, accepting just tok::l_brace,
+ // tok::r_brace, tok::minus, tok::identifier (think C000) and
+ // tok::numeric_constant (0000) should be enough. But the spelling of the
+ // uuid argument is checked later anyways, so there's no harm in accepting
+ // almost anything here.
+ // cl is very strict about whitespace in this form and errors out if any
+ // is present, so check the space flags on the tokens.
+ SourceLocation StartLoc = Tok.getLocation();
+ while (Tok.isNot(tok::r_paren)) {
+ if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) {
+ Diag(Tok, diag::err_attribute_uuid_malformed_guid);
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ SmallString<16> SpellingBuffer;
+ SpellingBuffer.resize(Tok.getLength() + 1);
+ bool Invalid = false;
+ StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid);
+ if (Invalid) {
+ SkipUntil(tok::r_paren, StopAtSemi);
+ return;
+ }
+ StrBuffer += TokSpelling;
+ ConsumeAnyToken();
+ }
+ StrBuffer += "\"";
+
+ if (Tok.hasLeadingSpace() || Tok.isAtStartOfLine()) {
+ Diag(Tok, diag::err_attribute_uuid_malformed_guid);
+ ConsumeParen();
+ return;
+ }
+
+ // Pretend the user wrote the appropriate string literal here.
+ // ActOnStringLiteral() copies the string data into the literal, so it's
+ // ok that the Token points to StrBuffer.
+ Token Toks[1];
+ Toks[0].startToken();
+ Toks[0].setKind(tok::string_literal);
+ Toks[0].setLocation(StartLoc);
+ Toks[0].setLiteralData(StrBuffer.data());
+ Toks[0].setLength(StrBuffer.size());
+ StringLiteral *UuidString =
+ cast<StringLiteral>(Actions.ActOnStringLiteral(Toks, nullptr).get());
+ ArgExprs.push_back(UuidString);
+ }
+
+ if (!T.consumeClose()) {
+ // FIXME: Warn that this syntax is deprecated, with a Fix-It suggesting
+ // using __declspec(uuid()) instead.
+ Attrs.addNew(UuidIdent, SourceRange(UuidLoc, T.getCloseLocation()), nullptr,
+ SourceLocation(), ArgExprs.data(), ArgExprs.size(),
+ AttributeList::AS_Microsoft);
+ }
+}
+
/// ParseMicrosoftAttributes - Parse Microsoft attributes [Attr]
///
/// [MS] ms-attribute:
// FIXME: If this is actually a C++11 attribute, parse it as one.
BalancedDelimiterTracker T(*this, tok::l_square);
T.consumeOpen();
- SkipUntil(tok::r_square, StopAtSemi | StopBeforeMatch);
+
+ // Skip most ms attributes except for a whitelist.
+ while (true) {
+ SkipUntil(tok::r_square, tok::identifier, StopAtSemi | StopBeforeMatch);
+ if (Tok.isNot(tok::identifier)) // ']', but also eof
+ break;
+ if (Tok.getIdentifierInfo()->getName() == "uuid")
+ ParseMicrosoftUuidAttributeArgs(attrs);
+ else
+ ConsumeToken();
+ }
+
T.consumeClose();
if (endLoc)
*endLoc = T.getCloseLocation();
// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID
+// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DBRACKET_ATTRIB -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-GUID
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=i386-pc-linux -fms-extensions | FileCheck %s
// RUN: %clang_cc1 -emit-llvm %s -o - -triple=x86_64-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-64
// RUN: %clang_cc1 -emit-llvm %s -o - -DDEFINE_GUID -DWRONG_GUID -triple=i386-pc-linux -fms-extensions | FileCheck %s --check-prefix=CHECK-DEFINE-WRONG-GUID
#endif
typedef struct _GUID GUID;
+#ifdef BRACKET_ATTRIB
+[uuid(12345678-1234-1234-1234-1234567890aB)] struct S1 { } s1;
+[uuid(87654321-4321-4321-4321-ba0987654321)] struct S2 { };
+[uuid({12345678-1234-1234-1234-1234567890ac})] struct Curly;
+[uuid({12345678-1234-1234-1234-1234567890ac})] struct Curly;
+#else
struct __declspec(uuid("12345678-1234-1234-1234-1234567890aB")) S1 { } s1;
struct __declspec(uuid("87654321-4321-4321-4321-ba0987654321")) S2 { };
struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
struct __declspec(uuid("{12345678-1234-1234-1234-1234567890ac}")) Curly;
+#endif
#ifdef DEFINE_GUID
// Make sure we can properly generate code when the UUID has curly braces on it.
struct __declspec(uuid("0000000-0000-0000-1234-0000500000047")) uuid_attr_bad3 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("0000000-0000-0000-Z234-000000000047")) uuid_attr_bad4 { };// expected-error {{uuid attribute contains a malformed GUID}}
struct __declspec(uuid("000000000000-0000-1234-000000000047")) uuid_attr_bad5 { };// expected-error {{uuid attribute contains a malformed GUID}}
+[uuid("000000000000-0000-1234-000000000047")] struct uuid_attr_bad6 { };// expected-error {{uuid attribute contains a malformed GUID}}
__declspec(uuid("000000A0-0000-0000-C000-000000000046")) int i; // expected-warning {{'uuid' attribute only applies to classes}}
struct __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
struct_with_uuid2;
+[uuid("000000A0-0000-0000-C000-000000000049")] struct struct_with_uuid3;
+
struct
struct_with_uuid2 {} ;
__uuidof(struct_with_uuid);
__uuidof(struct_with_uuid2);
+ __uuidof(struct_with_uuid3);
__uuidof(struct_without_uuid); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
__uuidof(struct_with_uuid*);
__uuidof(struct_without_uuid*); // expected-error {{cannot call operator __uuidof on a type with no GUID}}
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify -fms-extensions %s
+
+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 {};
+
+
+// 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;
+
+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);
+}
+}
+
+// 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];
+}
struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {}; /* expected-error {{'uuid' attribute is not supported in C}} */
+[uuid("00000000-0000-0000-C000-000000000046")] struct IUnknown2 {}; /* expected-error {{'uuid' attribute is not supported in C}} */
+
typedef struct notnested {
long bad1;
long bad2;