Index: lib/AST/DeclCXX.cpp =================================================================== --- lib/AST/DeclCXX.cpp +++ lib/AST/DeclCXX.cpp @@ -1470,6 +1470,15 @@ 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 @@ // 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(); - 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" && Index: test/SemaCXX/ms-iunknown-template-function.cpp =================================================================== --- test/SemaCXX/ms-iunknown-template-function.cpp +++ test/SemaCXX/ms-iunknown-template-function.cpp @@ -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 + HRESULT __stdcall QueryInterface(Q **pp) { + return QueryInterface(__uuidof(Q), (void **)pp); + } +}; +} +} + +__interface ISfFileIOPropertyPage : public IUnknown{}; + Index: test/SemaCXX/ms-iunknown.cpp =================================================================== --- test/SemaCXX/ms-iunknown.cpp +++ test/SemaCXX/ms-iunknown.cpp @@ -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 + void bar(T t){} }; + struct IPropertyPageBase : public IUnknown {}; struct IPropertyPage : public IPropertyPageBase {}; __interface ISfFileIOPropertyPage : public IPropertyPage {}; @@ -11,10 +15,17 @@ 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 @@ 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{};