]> granicus.if.org Git - clang/commitdiff
[Sema] Correct IUnknown to support Unknwnbase.h Header.
authorErich Keane <erich.keane@intel.com>
Fri, 29 Sep 2017 21:06:00 +0000 (21:06 +0000)
committerErich Keane <erich.keane@intel.com>
Fri, 29 Sep 2017 21:06:00 +0000 (21:06 +0000)
Apparently, the MSVC SDK has a strange implementation that
causes a number of implicit functions as well as a template member
function of the IUnknown type. This patch allows these as InterfaceLike
types as well.

Additionally, it corrects the behavior where extern-C++ wrapped around an
Interface-Like type would permit an interface-like type to exist in a namespace.

Differential Revision: https://reviews.llvm.org/D38303

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@314557 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/DeclCXX.cpp
test/SemaCXX/ms-iunknown-template-function.cpp [new file with mode: 0644]
test/SemaCXX/ms-iunknown.cpp

index e85ab418514706236473fde1b85fde31bbdde37b..a9759b4c0a202a60c1b0e83abd8a5918116d99c9 100644 (file)
@@ -1470,6 +1470,15 @@ bool CXXRecordDecl::isAnyDestructorNoReturn() const {
   return false;
 }
 
+static bool isDeclContextInNamespace(const DeclContext *DC) {
+  while (!DC->isTranslationUnit()) {
+    if (DC->isNamespace())
+      return true;
+    DC = DC->getParent();
+  }
+  return false;
+}
+
 bool CXXRecordDecl::isInterfaceLike() const {
   assert(hasDefinition() && "checking for interface-like without a definition");
   // All __interfaces are inheritently interface-like.
@@ -1486,13 +1495,16 @@ bool CXXRecordDecl::isInterfaceLike() const {
 
   // No interface-like type can have a method with a definition.
   for (const auto *const Method : methods())
-    if (Method->isDefined())
+    if (Method->isDefined() && !Method->isImplicit())
       return false;
 
   // Check "Special" types.
   const auto *Uuid = getAttr<UuidAttr>();
-  if (Uuid && isStruct() && (getDeclContext()->isTranslationUnit() ||
-                             getDeclContext()->isExternCXXContext()) &&
+  // MS SDK declares IUnknown/IDispatch both in the root of a TU, or in an
+  // extern C++ block directly in the TU.  These are only valid if in one
+  // of these two situations.
+  if (Uuid && isStruct() && !getDeclContext()->isExternCContext() &&
+      !isDeclContextInNamespace(getDeclContext()) &&
       ((getName() == "IUnknown" &&
         Uuid->getGuid() == "00000000-0000-0000-C000-000000000046") ||
        (getName() == "IDispatch" &&
diff --git a/test/SemaCXX/ms-iunknown-template-function.cpp b/test/SemaCXX/ms-iunknown-template-function.cpp
new file mode 100644 (file)
index 0000000..dc19223
--- /dev/null
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s 
+typedef long HRESULT;
+typedef unsigned long ULONG;
+typedef struct _GUID {
+  unsigned long Data1;
+  unsigned short Data2;
+  unsigned short Data3;
+  unsigned char Data4[8];
+} GUID;
+typedef GUID IID;
+
+// remove stdcall, since the warnings have nothing to do with
+// what is being tested.
+#define __stdcall
+
+extern "C" {
+extern "C++" {
+// expected-warning@+1 {{__declspec attribute 'novtable'}}
+struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) __declspec(novtable)
+    IUnknown {
+public:
+  virtual HRESULT __stdcall QueryInterface(
+      const IID &riid,
+      void **ppvObject) = 0;
+
+  virtual ULONG __stdcall AddRef(void) = 0;
+
+  virtual ULONG __stdcall Release(void) = 0;
+
+  template <class Q>
+  HRESULT __stdcall QueryInterface(Q **pp) {
+    return QueryInterface(__uuidof(Q), (void **)pp);
+  }
+};
+}
+}
+
+__interface ISfFileIOPropertyPage : public IUnknown{};
+
index f73864d43fb48d654b79e5756a084685667264ed..df761d56a80013db06b2cf134918949a9fde7da9 100644 (file)
@@ -2,7 +2,11 @@
 
 extern "C++" struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
   void foo();
+  // Definitions aren't allowed, unless they are a template.
+  template<typename T>
+  void bar(T t){}
 };
+
 struct IPropertyPageBase : public IUnknown {};
 struct IPropertyPage : public IPropertyPageBase {};
 __interface ISfFileIOPropertyPage : public IPropertyPage {};
@@ -11,10 +15,17 @@ __interface ISfFileIOPropertyPage : public IPropertyPage {};
 namespace NS {
   struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {};
   // expected-error@+1 {{interface type cannot inherit from}}
-  __interface IPropertyPageBase : public IUnknown {}; 
+  __interface IPropertyPageBase : public IUnknown {};
 }
+
+namespace NS2 {
+extern "C++" struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {};
+// expected-error@+1 {{interface type cannot inherit from}}
+__interface IPropertyPageBase : public IUnknown{};
+}
+
 // expected-error@+1 {{interface type cannot inherit from}}
-__interface IPropertyPageBase2 : public NS::IUnknown {}; 
+__interface IPropertyPageBase2 : public NS::IUnknown {};
 
 __interface temp_iface {};
 struct bad_base : temp_iface {};
@@ -32,8 +43,8 @@ __interface PropertyPage : public Page4 {};
 
 struct Page5 : public Page3, Page4{};
 // expected-error@+1 {{interface type cannot inherit from}}
-__interface PropertyPage2 : public Page5 {}; 
+__interface PropertyPage2 : public Page5 {};
 
 __interface IF1 {};
-__interface PP : IUnknown, IF1{}; 
+__interface PP : IUnknown, IF1{};
 __interface PP2 : PP, Page3, Page4{};