Skip to content

Commit

Permalink
Fix the __interface inheritence rules to work better with IUnknown an…
Browse files Browse the repository at this point in the history
…d 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
  • Loading branch information
Erich Keane committed Sep 15, 2017
1 parent f34537d commit 58bd603
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 1 deletion.
4 changes: 4 additions & 0 deletions clang/include/clang/AST/DeclCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,10 @@ class CXXRecordDecl : public RecordDecl {
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;
Expand Down
47 changes: 47 additions & 0 deletions clang/lib/AST/DeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions clang/test/SemaCXX/ms-iunknown-inline-def.cpp
Original file line number Diff line number Diff line change
@@ -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 {};
10 changes: 10 additions & 0 deletions clang/test/SemaCXX/ms-iunknown-outofline-def.cpp
Original file line number Diff line number Diff line change
@@ -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 {};
39 changes: 39 additions & 0 deletions clang/test/SemaCXX/ms-iunknown.cpp
Original file line number Diff line number Diff line change
@@ -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{};

0 comments on commit 58bd603

Please sign in to comment.