summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/DeclCXX.h4
-rw-r--r--clang/lib/AST/DeclCXX.cpp47
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp2
-rw-r--r--clang/test/SemaCXX/ms-iunknown-inline-def.cpp8
-rw-r--r--clang/test/SemaCXX/ms-iunknown-outofline-def.cpp10
-rw-r--r--clang/test/SemaCXX/ms-iunknown.cpp39
6 files changed, 109 insertions, 1 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index bbd3360d755..e2391d785d9 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -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;
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<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);
}
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<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.
diff --git a/clang/test/SemaCXX/ms-iunknown-inline-def.cpp b/clang/test/SemaCXX/ms-iunknown-inline-def.cpp
new file mode 100644
index 00000000000..70f1107c2e3
--- /dev/null
+++ b/clang/test/SemaCXX/ms-iunknown-inline-def.cpp
@@ -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 {};
diff --git a/clang/test/SemaCXX/ms-iunknown-outofline-def.cpp b/clang/test/SemaCXX/ms-iunknown-outofline-def.cpp
new file mode 100644
index 00000000000..b6e74d0eb60
--- /dev/null
+++ b/clang/test/SemaCXX/ms-iunknown-outofline-def.cpp
@@ -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 {};
diff --git a/clang/test/SemaCXX/ms-iunknown.cpp b/clang/test/SemaCXX/ms-iunknown.cpp
new file mode 100644
index 00000000000..c965a4c0a1b
--- /dev/null
+++ b/clang/test/SemaCXX/ms-iunknown.cpp
@@ -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{};
OpenPOWER on IntegriCloud