Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -2373,6 +2373,40 @@ return true; } +/// \brief Tests if RD is a public interface. +static bool IsDeclPublicInterface(const CXXRecordDecl *RD, + AccessSpecifier spec) { + return RD->isInterface() && spec == AS_public; +} + +/// \brief Test if record is a uuid for IUnknown. +/// This is an MS SDK specific type that has a special +/// behavior in the CL compiler. +static bool IsIUnknownType(const CXXRecordDecl *RD) { + const auto *Uuid = RD->getAttr(); + + return Uuid && RD->isStruct() && RD->isEmpty() && + RD->getDeclContext()->isTranslationUnit() && + RD->getName() == "IUnknown" && + Uuid->getGuid() =="00000000-0000-0000-C000-000000000046"; +} + +/// \brief Test if RD or its inherited bases is an IUnknown type. +static bool IsOrInheritsFromIUnknown(const CXXRecordDecl *RD) { + bool IsUnknown = IsIUnknownType(RD); + for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), + BaseEnd = RD->bases_end(); + Base != BaseEnd; ++Base) { + CXXRecordDecl *BaseChild = Base->getType()->getAsCXXRecordDecl(); + + return IsUnknown || + IsOrInheritsFromIUnknown(BaseChild) || + (RD->getNumBases() > 1) && + IsOrInheritsFromIUnknown((CXXRecordDecl*) BaseChild->getNextDeclInContext()); + } + return IsUnknown; +} + /// Use small set to collect indirect bases. As this is only used /// locally, there's no need to abstract the small size parameter. typedef llvm::SmallPtrSet IndirectBaseSet; @@ -2450,10 +2484,10 @@ if (const RecordType *Record = NewBaseType->getAs()) { const CXXRecordDecl *RD = cast(Record->getDecl()); if (Class->isInterface() && - (!RD->isInterface() || - KnownBase->getAccessSpecifier() != AS_public)) { - // The Microsoft extension __interface does not permit bases that - // are not themselves public interfaces. + // The Microsoft extension __interface does not permit bases that + // are not themselves public interfaces. + !IsDeclPublicInterface(RD, KnownBase->getAccessSpecifier()) && + !IsOrInheritsFromIUnknown(RD)) { Diag(KnownBase->getLocStart(), diag::err_invalid_base_in_interface) << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getName() << RD->getSourceRange();