From 58bd603109e4e6ca214712ca897d024bed07ef0f Mon Sep 17 00:00:00 2001 From: Erich Keane Date: Fri, 15 Sep 2017 16:03:35 +0000 Subject: 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 --- clang/lib/AST/DeclCXX.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++ clang/lib/Sema/SemaDeclCXX.cpp | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) (limited to 'clang/lib') diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 5782b7b56c9..d63d42c66ff 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -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(); + 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); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 941930c51ae..a9ef333c66e 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2388,7 +2388,7 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, if (const RecordType *Record = NewBaseType->getAs()) { const CXXRecordDecl *RD = cast(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. -- cgit v1.2.3