]> granicus.if.org Git - clang/commitdiff
__uuidof() and declspec(uuid("...")) should be allowed on enumeration types
authorReid Kleckner <rnk@google.com>
Tue, 13 Dec 2016 18:58:09 +0000 (18:58 +0000)
committerReid Kleckner <rnk@google.com>
Tue, 13 Dec 2016 18:58:09 +0000 (18:58 +0000)
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
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/AttributeList.h
lib/Sema/SemaDeclAttr.cpp
lib/Sema/SemaExprCXX.cpp
test/Parser/MicrosoftExtensions.cpp

index 46924959c2df81e94e1d70345840542bf0a90a1b..4c8276a553fa03239bb3523b35672e04bfa86069 100644 (file)
@@ -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];
 }
index cc8d5d4c03f6ae3122245dbdd01377999e68d586..84987401461f479c9441e06aa0caae83c6693711 100644 (file)
@@ -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<IgnoredAttributes>;
 def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Text>;
 def warn_type_attribute_wrong_type : Warning<
index 0c56b3fa346973cec2746ebb544a06b76f34358b..e74bf6a7cc8652ba622da1727dd4540094972f3a 100644 (file)
@@ -925,7 +925,8 @@ enum AttributeDeclKind {
   ExpectedVariableEnumFieldOrTypedef,
   ExpectedFunctionMethodEnumOrClass,
   ExpectedStructClassVariableFunctionOrInlineNamespace,
-  ExpectedForMaybeUnused
+  ExpectedForMaybeUnused,
+  ExpectedEnumOrClass,
 };
 
 }  // end namespace clang
index ffb1051bb48b09d1bd3ec1f71a89ac5502f56213..2ecea5fd6977e601089477bf7e08da840dc63654 100644 (file)
@@ -4666,12 +4666,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) {
     return;
   }
 
-  if (!isa<CXXRecordDecl>(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))
index 6acbd747dd6443ec5b225d83206786b5f158668a..a4546cec5abde197ab2ebe917889d91d11d011a0 100644 (file)
@@ -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<UuidAttr>()) {
+  if (const auto *Uuid = TD->getMostRecentDecl()->getAttr<UuidAttr>()) {
     UuidAttrs.insert(Uuid);
     return;
   }
 
   // __uuidof can grab UUIDs from template arguments.
-  if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+  if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) {
     const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
     for (const TemplateArgument &TA : TAL.asArray()) {
       const UuidAttr *UuidForTA = nullptr;
index 4aba8f0948edc4e1a68bdd443753c596f380cb03..830412ed474f631e066081be7d0fa6ebe188a0fc 100644 (file)
@@ -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]);