Fix the __interface inheritence rules to work better with IUnknown and IDispatch

__interface objects in MSVC are permitted to inherit from __interface types, 
and interface-like types.

Additionally, there are two default interface-like types 
(IUnknown and IDispatch) that all interface-like
types must inherit from.

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

llvm-svn: 313364
This commit is contained in:
Erich Keane 2017-09-15 16:03:35 +00:00
parent f34537dff8
commit 58bd603109
6 changed files with 109 additions and 1 deletions

View File

@ -1831,6 +1831,10 @@ public:
return getLambdaData().MethodTyInfo;
}
// \brief Determine whether this type is an Interface Like type for
// __interface inheritence purposes.
bool isInterfaceLike() const;
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
static bool classofKind(Kind K) {
return K >= firstCXXRecord && K <= lastCXXRecord;

View File

@ -1470,6 +1470,53 @@ bool CXXRecordDecl::isAnyDestructorNoReturn() const {
return false;
}
bool CXXRecordDecl::isInterfaceLike() const {
assert(hasDefinition() && "checking for interface-like without a definition");
// All __interfaces are inheritently interface-like.
if (isInterface())
return true;
// Interface-like types cannot have a user declared constructor, destructor,
// friends, VBases, conversion functions, or fields. Additionally, lambdas
// cannot be interface types.
if (isLambda() || hasUserDeclaredConstructor() ||
hasUserDeclaredDestructor() || !field_empty() || hasFriends() ||
getNumVBases() > 0 || conversion_end() - conversion_begin() > 0)
return false;
// No interface-like type can have a method with a definition.
for (const auto *const Method : methods())
if (Method->isDefined())
return false;
// Check "Special" types.
const auto *Uuid = getAttr<UuidAttr>();
if (Uuid && isStruct() && getDeclContext()->isTranslationUnit() &&
((getName() == "IUnknown" &&
Uuid->getGuid() == "00000000-0000-0000-C000-000000000046") ||
(getName() == "IDispatch" &&
Uuid->getGuid() == "00020400-0000-0000-C000-000000000046"))) {
if (getNumBases() > 0)
return false;
return true;
}
// FIXME: Any access specifiers is supposed to make this no longer interface
// like.
// If this isn't a 'special' type, it must have a single interface-like base.
if (getNumBases() != 1)
return false;
const auto BaseSpec = *bases_begin();
if (BaseSpec.isVirtual() || BaseSpec.getAccessSpecifier() != AS_public)
return false;
const auto *Base = BaseSpec.getType()->getAsCXXRecordDecl();
if (Base->isInterface() || !Base->isInterfaceLike())
return false;
return true;
}
void CXXRecordDecl::completeDefinition() {
completeDefinition(nullptr);
}

View File

@ -2388,7 +2388,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class,
if (const RecordType *Record = NewBaseType->getAs<RecordType>()) {
const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
if (Class->isInterface() &&
(!RD->isInterface() ||
(!RD->isInterfaceLike() ||
KnownBase->getAccessSpecifier() != AS_public)) {
// The Microsoft extension __interface does not permit bases that
// are not themselves public interfaces.

View File

@ -0,0 +1,8 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
void foo() {}
};
// expected-error@+1{{interface type cannot inherit from}}
__interface HasError : public IUnknown {};

View File

@ -0,0 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
void foo();
};
__interface NoError : public IUnknown {};
void IUnknown::foo() {}
// expected-error@+1{{interface type cannot inherit from}}
__interface HasError : public IUnknown {};

View File

@ -0,0 +1,39 @@
// RUN: %clang_cc1 -fsyntax-only -verify -fms-extensions %s
struct __declspec(uuid("00000000-0000-0000-C000-000000000046")) IUnknown {
void foo();
};
struct IPropertyPageBase : public IUnknown {};
struct IPropertyPage : public IPropertyPageBase {};
__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 {};
}
// expected-error@+1 {{interface type cannot inherit from}}
__interface IPropertyPageBase2 : public NS::IUnknown {};
__interface temp_iface {};
struct bad_base : temp_iface {};
// expected-error@+1 {{interface type cannot inherit from}}
__interface bad_inherit : public bad_base{};
struct mult_inher_base : temp_iface, IUnknown {};
// expected-error@+1 {{interface type cannot inherit from}}
__interface bad_inherit2 : public mult_inher_base{};
struct PageBase : public IUnknown {};
struct Page3 : public PageBase {};
struct Page4 : public PageBase {};
__interface PropertyPage : public Page4 {};
struct Page5 : public Page3, Page4{};
// expected-error@+1 {{interface type cannot inherit from}}
__interface PropertyPage2 : public Page5 {};
__interface IF1 {};
__interface PP : IUnknown, IF1{};
__interface PP2 : PP, Page3, Page4{};