mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-19 13:26:45 +00:00
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:
parent
f34537dff8
commit
58bd603109
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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.
|
||||
|
8
clang/test/SemaCXX/ms-iunknown-inline-def.cpp
Normal file
8
clang/test/SemaCXX/ms-iunknown-inline-def.cpp
Normal 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 {};
|
10
clang/test/SemaCXX/ms-iunknown-outofline-def.cpp
Normal file
10
clang/test/SemaCXX/ms-iunknown-outofline-def.cpp
Normal 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 {};
|
39
clang/test/SemaCXX/ms-iunknown.cpp
Normal file
39
clang/test/SemaCXX/ms-iunknown.cpp
Normal 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{};
|
Loading…
x
Reference in New Issue
Block a user