diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Sema/AttributeList.h | 13 | ||||
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 2 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 16 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 19 | ||||
| -rw-r--r-- | clang/test/SemaCXX/ms-uuid.cpp | 94 |
7 files changed, 152 insertions, 4 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 0537c48617a..36249022192 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -2255,6 +2255,8 @@ def err_attribute_only_once_per_parameter : Error< "%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>; diff --git a/clang/include/clang/Sema/AttributeList.h b/clang/include/clang/Sema/AttributeList.h index f115c722a6e..ff04f264964 100644 --- a/clang/include/clang/Sema/AttributeList.h +++ b/clang/include/clang/Sema/AttributeList.h @@ -748,6 +748,19 @@ public: 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; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 92d669c7491..9c2030b5860 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2208,6 +2208,8 @@ public: 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, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 86f7abafeb5..71cbc451e1c 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1439,6 +1439,8 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs, ParsedAttributes &PA = DS.getAttributes(); AttributeList *AL = PA.getList(); AttributeList *Prev = nullptr; + AttributeList *TypeAttrHead = nullptr; + AttributeList *TypeAttrTail = nullptr; while (AL) { AttributeList *Next = AL->getNext(); @@ -1446,8 +1448,12 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs, 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) { @@ -1465,6 +1471,12 @@ void Parser::stripTypeAttributesOffDeclSpec(ParsedAttributesWithRange &Attrs, 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 diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 0c2540b9b71..3014369c887 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -2246,6 +2246,13 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) { 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)) @@ -2304,6 +2311,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, (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)); diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 824d68e838e..c23db571415 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4604,6 +4604,19 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, // 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) @@ -4645,8 +4658,10 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } - 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) { diff --git a/clang/test/SemaCXX/ms-uuid.cpp b/clang/test/SemaCXX/ms-uuid.cpp new file mode 100644 index 00000000000..2192f67eabc --- /dev/null +++ b/clang/test/SemaCXX/ms-uuid.cpp @@ -0,0 +1,94 @@ +// 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; +} |

