From 14f4b9d4f054e650d191222501bfdbdd6e5302b8 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Tue, 13 Dec 2016 18:58:09 +0000 Subject: [PATCH] __uuidof() and declspec(uuid("...")) should be allowed on enumeration types MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Although not specifically mentioned in the documentation, MSVC accepts __uuidof(…) and declspec(uuid("…")) attributes on enumeration types in addition to structs/classes. This is meaningful, as such types *do* have associated UUIDs in ActiveX typelibs, and such attributes are included by default in the wrappers generated by their #import construct, so they are not particularly unusual. clang currently rejects the declspec with a –Wignored-attributes warning, and errors on __uuidof() with “cannot call operator __uuidof on a type with no GUID” (because it rejected the uuid attribute, and therefore finds no value). This is causing problems for us while trying to use clang-tidy on a codebase that makes heavy use of ActiveX. I believe I have found the relevant places to add this functionality, this patch adds this case to clang’s implementation of these MS extensions. patch is against r285994 (or actually the git mirror 80464680ce). Both include an update to test/Parser/MicrosoftExtensions.cpp to exercise the new functionality. This is my first time contributing to LLVM, so if I’ve missed anything else needed to prepare this for review just let me know! __uuidof: https://msdn.microsoft.com/en-us/library/zaah6a61.aspx declspec(uuid("…")): https://msdn.microsoft.com/en-us/library/3b6wkewa.aspx #import: https://msdn.microsoft.com/en-us/library/8etzzkb6.aspx Reviewers: aaron.ballman, majnemer, rnk Differential Revision: https://reviews.llvm.org/D26846 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289567 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 4 +++- include/clang/Basic/DiagnosticSemaKinds.td | 3 ++- include/clang/Sema/AttributeList.h | 3 ++- lib/Sema/SemaDeclAttr.cpp | 6 ------ lib/Sema/SemaExprCXX.cpp | 8 ++++---- test/Parser/MicrosoftExtensions.cpp | 15 +++++++++++++++ 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 46924959c2..4c8276a553 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -1618,7 +1618,9 @@ def Used : InheritableAttr { def Uuid : InheritableAttr { let Spellings = [Declspec<"uuid">, Microsoft<"uuid">]; let Args = [StringArgument<"Guid">]; -// let Subjects = SubjectList<[CXXRecord]>; + let Subjects = SubjectList<[Record, Enum], WarnDiag, "ExpectedEnumOrClass">; + // FIXME: Allow expressing logical AND for LangOpts. Our condition should be: + // CPlusPlus && (MicrosoftExt || Borland) let LangOpts = [MicrosoftExt, Borland]; let Documentation = [Undocumented]; } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index cc8d5d4c03..8498740146 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -2650,7 +2650,8 @@ def warn_attribute_wrong_decl_type : Warning< "|variables, enums, fields and typedefs" "|functions, methods, enums, and classes" "|structs, classes, variables, functions, and inline namespaces" - "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members}1">, + "|variables, functions, methods, types, enumerations, enumerators, labels, and non-static data members" + "|classes and enumerations}1">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< diff --git a/include/clang/Sema/AttributeList.h b/include/clang/Sema/AttributeList.h index 0c56b3fa34..e74bf6a7cc 100644 --- a/include/clang/Sema/AttributeList.h +++ b/include/clang/Sema/AttributeList.h @@ -925,7 +925,8 @@ enum AttributeDeclKind { ExpectedVariableEnumFieldOrTypedef, ExpectedFunctionMethodEnumOrClass, ExpectedStructClassVariableFunctionOrInlineNamespace, - ExpectedForMaybeUnused + ExpectedForMaybeUnused, + ExpectedEnumOrClass, }; } // end namespace clang diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index ffb1051bb4..2ecea5fd69 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -4666,12 +4666,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (!isa(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedClass; - return; - } - StringRef StrRef; SourceLocation LiteralLoc; if (!S.checkStringLiteralArgumentAttr(Attr, 0, StrRef, &LiteralLoc)) diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 6acbd747dd..a4546cec5a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -520,17 +520,17 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); - const auto *RD = Ty->getAsCXXRecordDecl(); - if (!RD) + const auto *TD = Ty->getAsTagDecl(); + if (!TD) return; - if (const auto *Uuid = RD->getMostRecentDecl()->getAttr()) { + if (const auto *Uuid = TD->getMostRecentDecl()->getAttr()) { UuidAttrs.insert(Uuid); return; } // __uuidof can grab UUIDs from template arguments. - if (const auto *CTSD = dyn_cast(RD)) { + if (const auto *CTSD = dyn_cast(TD)) { const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); for (const TemplateArgument &TA : TAL.asArray()) { const UuidAttr *UuidForTA = nullptr; diff --git a/test/Parser/MicrosoftExtensions.cpp b/test/Parser/MicrosoftExtensions.cpp index 4aba8f0948..830412ed47 100644 --- a/test/Parser/MicrosoftExtensions.cpp +++ b/test/Parser/MicrosoftExtensions.cpp @@ -65,6 +65,12 @@ struct_with_uuid2; struct struct_with_uuid2 {} ; +enum __declspec(uuid("000000A0-0000-0000-C000-000000000046")) +enum_with_uuid { }; +enum enum_without_uuid { }; + +int __declspec(uuid("000000A0-0000-0000-C000-000000000046")) inappropriate_uuid; // expected-warning {{'uuid' attribute only applies to classes and enumerations}} + int uuid_sema_test() { struct_with_uuid var_with_uuid[1]; @@ -81,6 +87,15 @@ int uuid_sema_test() __uuidof(const struct_with_uuid[1][1]); __uuidof(const struct_with_uuid*[1][1]); // expected-error {{cannot call operator __uuidof on a type with no GUID}} + __uuidof(enum_with_uuid); + __uuidof(enum_without_uuid); // expected-error {{cannot call operator __uuidof on a type with no GUID}} + __uuidof(enum_with_uuid*); + __uuidof(enum_without_uuid*); // expected-error {{cannot call operator __uuidof on a type with no GUID}} + __uuidof(enum_with_uuid[1]); + __uuidof(enum_with_uuid*[1]); // expected-error {{cannot call operator __uuidof on a type with no GUID}} + __uuidof(const enum_with_uuid[1][1]); + __uuidof(const enum_with_uuid*[1][1]); // expected-error {{cannot call operator __uuidof on a type with no GUID}} + __uuidof(var_with_uuid); __uuidof(var_without_uuid);// expected-error {{cannot call operator __uuidof on a type with no GUID}} __uuidof(var_with_uuid[1]); -- 2.40.0