"%0 attribute can only be applied once per parameter">;
def err_attribute_uuid_malformed_guid : Error<
"uuid attribute contains a malformed GUID">;
+def err_mismatched_uuid : Error<"uuid does not match previous declaration">;
+def note_previous_uuid : Note<"previous uuid specified here">;
def warn_attribute_pointers_only : Warning<
"%0 attribute only applies to%select{| constant}1 pointer arguments">,
InGroup<IgnoredAttributes>;
list = newList;
}
+ void addAllAtEnd(AttributeList *newList) {
+ if (!list) {
+ list = newList;
+ return;
+ }
+
+ AttributeList *lastInList = list;
+ while (AttributeList *next = lastInList->getNext())
+ lastInList = next;
+
+ lastInList->setNext(newList);
+ }
+
void set(AttributeList *newList) {
list = newList;
}
VisibilityAttr *mergeVisibilityAttr(Decl *D, SourceRange Range,
VisibilityAttr::VisibilityType Vis,
unsigned AttrSpellingListIndex);
+ UuidAttr *mergeUuidAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex, StringRef Uuid);
DLLImportAttr *mergeDLLImportAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex);
DLLExportAttr *mergeDLLExportAttr(Decl *D, SourceRange Range,
ParsedAttributes &PA = DS.getAttributes();
AttributeList *AL = PA.getList();
AttributeList *Prev = nullptr;
+ AttributeList *TypeAttrHead = nullptr;
+ AttributeList *TypeAttrTail = nullptr;
while (AL) {
AttributeList *Next = AL->getNext();
AL->isDeclspecAttribute()) ||
AL->isMicrosoftAttribute()) {
// Stitch the attribute into the tag's attribute list.
- AL->setNext(nullptr);
- Attrs.add(AL);
+ if (TypeAttrTail)
+ TypeAttrTail->setNext(AL);
+ else
+ TypeAttrHead = AL;
+ TypeAttrTail = AL;
+ TypeAttrTail->setNext(nullptr);
// Remove the attribute from the variable's attribute list.
if (Prev) {
AL = Next;
}
+
+ // Find end of type attributes Attrs and add NewTypeAttributes in the same
+ // order they were in originally. (Remember, in AttributeList things earlier
+ // in source order are later in the list, since new attributes are added to
+ // the front of the list.)
+ Attrs.addAllAtEnd(TypeAttrHead);
}
/// ParseDeclaration - Parse a full 'declaration', which consists of
static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
const InheritableAttr *Attr,
Sema::AvailabilityMergeKind AMK) {
+ // This function copies an attribute Attr from a previous declaration to the
+ // new declaration D if the new declaration doesn't itself have that attribute
+ // yet or if that attribute allows duplicates.
+ // If you're adding a new attribute that requires logic different from
+ // "use explicit attribute on decl if present, else use attribute from
+ // previous decl", for example if the attribute needs to be consistent
+ // between redeclarations, you need to call a custom merge function here.
InheritableAttr *NewAttr = nullptr;
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
(AMK == Sema::AMK_Override ||
AMK == Sema::AMK_ProtocolImplementation))
NewAttr = nullptr;
+ else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
+ NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex,
+ UA->getGuid());
else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr))
NewAttr = cast<InheritableAttr>(Attr->clone(S.Context));
// Microsoft specific attribute handlers.
//===----------------------------------------------------------------------===//
+UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range,
+ unsigned AttrSpellingListIndex, StringRef Uuid) {
+ if (const auto *UA = D->getAttr<UuidAttr>()) {
+ if (UA->getGuid() == Uuid)
+ return nullptr;
+ Diag(UA->getLocation(), diag::err_mismatched_uuid);
+ Diag(Range.getBegin(), diag::note_previous_uuid);
+ D->dropAttr<UuidAttr>();
+ }
+
+ return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex);
+}
+
static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!S.LangOpts.CPlusPlus) {
S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang)
}
}
- D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context, StrRef,
- Attr.getAttributeSpellingListIndex()));
+ UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(),
+ Attr.getAttributeSpellingListIndex(), StrRef);
+ if (UA)
+ D->addAttr(UA);
}
static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) {
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
+
+typedef struct _GUID {
+ unsigned long Data1;
+ unsigned short Data2;
+ unsigned short Data3;
+ unsigned char Data4[8];
+} GUID;
+
+namespace {
+// cl.exe's behavior with merging uuid attributes is a bit erratic:
+// * In []-style attributes, a single [] list must not list a duplicate uuid
+// (even if it's the same uuid), and only a single declaration of a class
+// must have a uuid else the compiler errors out (even if two declarations of
+// a class have the same uuid).
+// * For __declspec(uuid(...)), it's ok if several declarations of a class have
+// an uuid, as long as it's the same uuid each time. If uuids on declarations
+// don't match, the compiler errors out.
+// * If there are several __declspec(uuid(...))s on one declaration, the
+// compiler only warns about this and uses the last uuid. It even warns if
+// the uuids are the same.
+
+// clang-cl implements the following simpler (but largely compatible) behavior
+// instead:
+// * [] and __declspec uuids have the same behavior.
+// * If there are several uuids on a a class (no matter if on the same decl or
+// on several decls), it is an error if they don't match.
+// * Having several uuids that match is ok.
+
+// Both cl and clang-cl accept this:
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1;
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1;
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C1 {};
+
+// Both cl and clang-cl error out on this:
+// expected-note@+1 2{{previous uuid specified here}}
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C2;
+// expected-error@+1 {{uuid does not match previous declaration}}
+class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C2;
+// expected-error@+1 {{uuid does not match previous declaration}}
+class __declspec(uuid("220000A0-0000-0000-C000-000000000049")) C2 {};
+
+// expected-note@+1 {{previous uuid specified here}}
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C2_2;
+class C2_2;
+// expected-error@+1 {{uuid does not match previous declaration}}
+class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C2_2;
+
+// clang-cl accepts this, but cl errors out:
+[uuid("000000A0-0000-0000-C000-000000000049")] class C3;
+[uuid("000000A0-0000-0000-C000-000000000049")] class C3;
+[uuid("000000A0-0000-0000-C000-000000000049")] class C3 {};
+
+// Both cl and clang-cl error out on this (but for different reasons):
+// expected-note@+1 2{{previous uuid specified here}}
+[uuid("000000A0-0000-0000-C000-000000000049")] class C4;
+// expected-error@+1 {{uuid does not match previous declaration}}
+[uuid("110000A0-0000-0000-C000-000000000049")] class C4;
+// expected-error@+1 {{uuid does not match previous declaration}}
+[uuid("220000A0-0000-0000-C000-000000000049")] class C4 {};
+
+// Both cl and clang-cl error out on this:
+// expected-note@+1 {{previous uuid specified here}}
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
+// expected-error@+1 {{uuid does not match previous declaration}}
+ __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C5;
+
+// expected-note@+1 {{previous uuid specified here}}
+[uuid("000000A0-0000-0000-C000-000000000049"),
+// expected-error@+1 {{uuid does not match previous declaration}}
+ uuid("110000A0-0000-0000-C000-000000000049")] class C6;
+
+// cl doesn't diagnose having one uuid each as []-style attributes and as
+// __declspec, even if the uuids differ. clang-cl errors if they differ.
+[uuid("000000A0-0000-0000-C000-000000000049")]
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C7;
+
+// expected-note@+1 {{previous uuid specified here}}
+[uuid("000000A0-0000-0000-C000-000000000049")]
+// expected-error@+1 {{uuid does not match previous declaration}}
+class __declspec(uuid("110000A0-0000-0000-C000-000000000049")) C8;
+
+
+// cl warns on this, but clang-cl is fine with it (which is consistent with
+// e.g. specifying __multiple_inheritance several times, which cl accepts
+// without warning too).
+class __declspec(uuid("000000A0-0000-0000-C000-000000000049"))
+ __declspec(uuid("000000A0-0000-0000-C000-000000000049")) C9;
+
+// cl errors out on this, but clang-cl is fine with it (to be consistent with
+// the previous case).
+[uuid("000000A0-0000-0000-C000-000000000049"),
+ uuid("000000A0-0000-0000-C000-000000000049")] class C10;
+}