summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--clang/include/clang/Sema/AttributeList.h13
-rw-r--r--clang/include/clang/Sema/Sema.h2
-rw-r--r--clang/lib/Parse/ParseDecl.cpp16
-rw-r--r--clang/lib/Sema/SemaDecl.cpp10
-rw-r--r--clang/lib/Sema/SemaDeclAttr.cpp19
-rw-r--r--clang/test/SemaCXX/ms-uuid.cpp94
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;
+}
OpenPOWER on IntegriCloud