[cfe-dev] [PATCH] __interface support (with isVirtual fix)

David Robins llvm at davidrobins.net
Sat Aug 25 18:47:55 PDT 2012


Updated patch attached; patch also updated to be against current
revision (162644 at time of writing). All tests pass.

It removes the call to setVirtualAsWritten and instead, as suggested by
John McCall, modifies CXXMethodDecl::isVirtual to return true if either
virtual as written is set or the method is declared in an interface.

(As I noted before, I do not have commit access so if approved I will
need someone else to commit this change.)
-------------- next part --------------
Index: test/Parser/MicrosoftExtensions.cpp
===================================================================
--- test/Parser/MicrosoftExtensions.cpp	(revision 162644)
+++ test/Parser/MicrosoftExtensions.cpp	(working copy)
@@ -174,13 +174,21 @@
 
 __interface MicrosoftInterface;
 __interface MicrosoftInterface {
-   virtual void foo1() = 0;
+   void foo1() = 0;
    virtual void foo2() = 0;
 };
 
+__interface MicrosoftDerivedInterface : public MicrosoftInterface {
+  void foo1();
+  void foo2() override;
+  void foo3();
+};
+
 void interface_test() {
   MicrosoftInterface* a;
   a->foo1();
+  MicrosoftDerivedInterface* b;
+  b->foo2();
 }
 
 __int64 x7 = __int64(0);
Index: include/clang/Basic/Specifiers.h
===================================================================
--- include/clang/Basic/Specifiers.h	(revision 162644)
+++ include/clang/Basic/Specifiers.h	(working copy)
@@ -53,6 +53,7 @@
     TST_union,
     TST_struct,
     TST_class,        // C++ class type
+    TST_interface,    // C++ (Microsoft-specific) __interface type
     TST_typename,     // Typedef, C++ class-name or enum name, etc.
     TST_typeofType,
     TST_typeofExpr,
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def	(revision 162644)
+++ include/clang/Basic/TokenKinds.def	(working copy)
@@ -505,6 +505,7 @@
 KEYWORD(__single_inheritance          , KEYMS)
 KEYWORD(__multiple_inheritance        , KEYMS)
 KEYWORD(__virtual_inheritance         , KEYMS)
+KEYWORD(__interface                   , KEYMS)
 ALIAS("__int8"           , char       , KEYMS)
 ALIAS("__int16"          , short      , KEYMS)
 ALIAS("__int32"          , int        , KEYMS)
@@ -518,7 +519,6 @@
 ALIAS("_uuidof"          , __uuidof   , KEYMS | KEYBORLAND)
 ALIAS("_inline"          , inline     , KEYMS)
 ALIAS("_declspec"        , __declspec , KEYMS)
-ALIAS("__interface"      , struct     , KEYMS)
 
 // Borland Extensions which should be disabled in strict conformance mode.
 ALIAS("_pascal"      , __pascal   , KEYBORLAND)
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td	(revision 162644)
+++ include/clang/Basic/DiagnosticParseKinds.td	(working copy)
@@ -573,7 +573,7 @@
   "expected an identifier or template-id after '::'">;
 def err_explicit_spec_non_template : Error<
   "explicit %select{specialization|instantiation}0 of non-template "
-  "%select{class|struct|union}1 %2">;
+  "%select{class|struct|union|interface}1 %2">;
   
 def err_default_template_template_parameter_not_template : Error<
   "default template argument for a template template parameter must be a class "
Index: include/clang/Basic/DiagnosticASTKinds.td
===================================================================
--- include/clang/Basic/DiagnosticASTKinds.td	(revision 162644)
+++ include/clang/Basic/DiagnosticASTKinds.td	(working copy)
@@ -137,7 +137,7 @@
 def warn_odr_tag_type_inconsistent : Warning<
   "type %0 has incompatible definitions in different translation units">;
 def note_odr_tag_kind_here: Note<
-  "%0 is a %select{struct|union|class|enum}1 here">;
+  "%0 is a %select{struct|interface|union|class|enum}1 here">;
 def note_odr_field : Note<"field %0 has type %1 here">;
 def note_odr_missing_field : Note<"no corresponding field here">;
 def note_odr_bit_field : Note<"bit-field %0 with type %1 and length %2 here">;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td	(revision 162644)
+++ include/clang/Basic/DiagnosticSemaKinds.td	(working copy)
@@ -792,10 +792,11 @@
   "with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
 def ext_unelaborated_friend_type : ExtWarn<
   "unelaborated friend declaration is a C++11 extension; specify "
-  "'%select{struct|union|class|enum}0' to befriend %1">, InGroup<CXX11>;
+  "'%select{struct|interface|union|class|enum}0' to befriend %1">,
+  InGroup<CXX11>;
 def warn_cxx98_compat_unelaborated_friend_type : Warning<
-  "befriending %1 without '%select{struct|union|class|enum}0' keyword is "
-  "incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
+  "befriending %1 without '%select{struct|interface|union|class|enum}0' "
+  "keyword is incompatible with C++98">, InGroup<CXX98Compat>, DefaultIgnore;
 def err_qualified_friend_not_found : Error<
   "no function named %0 with type %1 was found in the specified scope">;
 def err_introducing_special_friend : Error<
@@ -1113,8 +1114,8 @@
 def err_constructor_byvalue_arg : Error<
   "copy constructor must pass its first argument by reference">;
 def warn_no_constructor_for_refconst : Warning<
-  "%select{struct|union|class|enum}0 %1 does not declare any constructor to "
-  "initialize its non-modifiable members">;
+  "%select{struct|interface|union|class|enum}0 %1 does not declare any "
+  "constructor to initialize its non-modifiable members">;
 def note_refconst_member_not_initialized : Note<
   "%select{const|reference}0 member %1 will never be initialized">;
 def ext_ms_explicit_constructor_call : ExtWarn<
@@ -1307,9 +1308,10 @@
   "cannot allocate array of 'auto'">;
 def err_auto_not_allowed : Error<
   "'auto' not allowed %select{in function prototype|in non-static struct member"
-  "|in non-static union member|in non-static class member|in exception declaration"
-  "|in template parameter|in block literal|in template argument"
-  "|in typedef|in type alias|in function return type|here}0">;
+  "|in non-static union member|in non-static class member|in interface member"
+  "|in exception declaration|in template parameter|in block literal"
+  "|in template argument|in typedef|in type alias|in function return type"
+  "|here}0">;
 def err_auto_var_requires_init : Error<
   "declaration of variable %0 with type %1 requires an initializer">;
 def err_auto_new_requires_ctor_arg : Error<
@@ -1435,7 +1437,7 @@
   "%select{function parameter|typedef|non-static data member}0 "
   "cannot be constexpr">;
 def err_constexpr_tag : Error<
-  "%select{class|struct|union|enum}0 cannot be marked constexpr">;
+  "%select{class|struct|interface|union|enum}0 cannot be marked constexpr">;
 def err_constexpr_dtor : Error<"destructor cannot be marked constexpr">;
 def err_constexpr_no_declarators : Error<
   "constexpr can only be used in variable and function declarations">;
@@ -1453,11 +1455,12 @@
 def err_constexpr_virtual : Error<"virtual function cannot be constexpr">;
 def err_constexpr_virtual_base : Error<
   "constexpr %select{member function|constructor}0 not allowed in "
-  "%select{class|struct}1 with virtual base %plural{1:class|:classes}2">;
+  "%select{struct|interface|class}1 with virtual base "
+  "%plural{1:class|:classes}2">;
 def note_non_literal_incomplete : Note<
   "incomplete type %0 is not a literal type">;
-def note_non_literal_virtual_base : Note<"%select{class|struct}0 with virtual "
-  "base %plural{1:class|:classes}1 is not a literal type">;
+def note_non_literal_virtual_base : Note<"%select{struct|interface|class}0 "
+  "with virtual base %plural{1:class|:classes}1 is not a literal type">;
 def note_constexpr_virtual_base_here : Note<"virtual base class declared here">;
 def err_constexpr_non_literal_return : Error<
   "constexpr function's return type %0 is not a literal type">;
@@ -1696,7 +1699,9 @@
   "attribute %0 cannot be specified on a statement">,
   InGroup<IgnoredAttributes>;
 def warn_declspec_attribute_ignored : Warning<
-  "attribute %0 is ignored, place it after \"%select{class|struct|union|enum}1\" to apply attribute to type declaration">, InGroup<IgnoredAttributes>;
+  "attribute %0 is ignored, place it after "
+  "\"%select{class|struct|union|interface|enum}1\" to apply attribute to "
+  "type declaration">, InGroup<IgnoredAttributes>;
 def warn_attribute_precede_definition : Warning<
   "attribute declaration must precede definition">,
   InGroup<IgnoredAttributes>;
@@ -3174,8 +3179,8 @@
   "implicit declaration introduced by elaborated type conflicts with "
   "%select{a declaration|a typedef|a type alias|a template}0 of the same name">;
 def err_dependent_tag_decl : Error<
-  "%select{declaration|definition}0 of %select{struct|union|class|enum}1 "
-  "in a dependent scope">;
+  "%select{declaration|definition}0 of "
+  "%select{struct|interface|union|class|enum}1 in a dependent scope">;
 def err_tag_definition_of_typedef : Error<
   "definition of type %0 conflicts with %select{typedef|type alias}1 of the same name">;
 def err_conflicting_types : Error<"conflicting types for %0">;
@@ -3183,15 +3188,16 @@
 def err_use_with_wrong_tag : Error<
   "use of %0 with tag type that does not match previous declaration">;
 def warn_struct_class_tag_mismatch : Warning<
-    "%select{struct|class}0%select{| template}1 %2 was previously declared "
-    "as a %select{class|struct}0%select{| template}1">,
+    "%select{struct|interface|class}0%select{| template}1 %2 was previously "
+    "declared as a %select{struct|interface|class}3%select{| template}1">,
     InGroup<MismatchedTags>, DefaultIgnore;
 def warn_struct_class_previous_tag_mismatch : Warning<
-    "%2 defined as a %select{struct|class}0%select{| template}1 here but "
-    "previously declared as a %select{class|struct}0%select{| template}1">,
+    "%2 defined as %select{a struct|an interface|a class}0%select{| template}1 "
+    "here but previously declared as "
+    "%select{a struct|an interface|a class}3%select{| template}1">,
      InGroup<MismatchedTags>, DefaultIgnore;
 def note_struct_class_suggestion : Note<
-    "did you mean %select{struct|class}0 here?">;
+    "did you mean %select{struct|interface|class}0 here?">;
 def ext_forward_ref_enum : Extension<
   "ISO C forbids forward references to 'enum' types">;
 def err_forward_ref_enum : Error<
@@ -3235,11 +3241,13 @@
 
 // -Wpadded, -Wpacked
 def warn_padded_struct_field : Warning<
-  "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 "
-  "to align %5">, InGroup<Padded>, DefaultIgnore;
+  "padding %select{struct|interface|class}0 %1 with %2 "
+  "%select{byte|bit}3%select{|s}4 to align %5">,
+  InGroup<Padded>, DefaultIgnore;
 def warn_padded_struct_anon_field : Warning<
-  "padding %select{struct|class}0 %1 with %2 %select{byte|bit}3%select{|s}4 "
-  "to align anonymous bit-field">, InGroup<Padded>, DefaultIgnore;
+  "padding %select{struct|interface|class}0 %1 with %2 "
+  "%select{byte|bit}3%select{|s}4 to align anonymous bit-field">,
+  InGroup<Padded>, DefaultIgnore;
 def warn_padded_struct_size : Warning<
   "padding size of %0 with %1 %select{byte|bit}2%select{|s}3 "
   "to alignment boundary">, InGroup<Padded>, DefaultIgnore;
@@ -3487,14 +3495,16 @@
 def err_flexible_array_init : Error<
   "initialization of flexible array member is not allowed">;
 def ext_flexible_array_empty_aggregate_ms : Extension<
-  "flexible array member %0 in otherwise empty %select{struct|class}1 "
-  "is a Microsoft extension">, InGroup<Microsoft>;
+  "flexible array member %0 in otherwise empty "
+  "%select{struct|interface|union|class|enum}1 is a Microsoft extension">,
+  InGroup<Microsoft>;
 def ext_flexible_array_union_ms : Extension<
   "flexible array member %0 in a union is a Microsoft extension">,
   InGroup<Microsoft>;
 def ext_flexible_array_empty_aggregate_gnu : Extension<
-  "flexible array member %0 in otherwise empty %select{struct|class}1 "
-  "is a GNU extension">, InGroup<GNU>;
+  "flexible array member %0 in otherwise empty "
+  "%select{struct|interface|union|class|enum}1 is a GNU extension">,
+  InGroup<GNU>;
 def ext_flexible_array_union_gnu : Extension<
   "flexible array member %0 in a union is a GNU extension">, InGroup<GNU>;
 
@@ -4577,7 +4587,7 @@
 def err_invalid_declarator_in_function : Error<
   "definition or redeclaration of %0 not allowed inside a function">;
 def err_not_tag_in_scope : Error<
-  "no %select{struct|union|class|enum}0 named %1 in %2">;
+  "no %select{struct|interface|union|class|enum}0 named %1 in %2">;
 
 def err_no_typeid_with_fno_rtti : Error<
   "cannot use typeid with -fno-rtti">;
@@ -5926,7 +5936,7 @@
   "%select{local variable|parameter|typedef}0 %1 cannot be declared "
   "__module_private__">;
 def err_module_private_local_class : Error<
-  "local %select{struct|union|class|enum}0 cannot be declared "
+  "local %select{struct|interface|union|class|enum}0 cannot be declared "
   "__module_private__">;
 def err_module_private_definition : Error<
   "definition of %0 must be imported before it is required">;
Index: include/clang/Sema/DeclSpec.h
===================================================================
--- include/clang/Sema/DeclSpec.h	(revision 162644)
+++ include/clang/Sema/DeclSpec.h	(working copy)
@@ -266,6 +266,7 @@
   static const TST TST_enum = clang::TST_enum;
   static const TST TST_union = clang::TST_union;
   static const TST TST_struct = clang::TST_struct;
+  static const TST TST_interface = clang::TST_interface;
   static const TST TST_class = clang::TST_class;
   static const TST TST_typename = clang::TST_typename;
   static const TST TST_typeofType = clang::TST_typeofType;
@@ -378,7 +379,8 @@
   }
   static bool isDeclRep(TST T) {
     return (T == TST_enum || T == TST_struct ||
-            T == TST_union || T == TST_class);
+            T == TST_interface || T == TST_union ||
+            T == TST_class);
   }
 
   DeclSpec(const DeclSpec&);       // DO NOT IMPLEMENT
Index: include/clang/AST/Type.h
===================================================================
--- include/clang/AST/Type.h	(revision 162644)
+++ include/clang/AST/Type.h	(working copy)
@@ -1512,6 +1512,7 @@
   bool isRecordType() const;
   bool isClassType() const;
   bool isStructureType() const;
+  bool isInterfaceType() const;
   bool isStructureOrClassType() const;
   bool isUnionType() const;
   bool isComplexIntegerType() const;            // GCC _Complex integer type.
@@ -3796,6 +3797,8 @@
 enum TagTypeKind {
   /// \brief The "struct" keyword.
   TTK_Struct,
+  /// \brief The "__interface" keyword.
+  TTK_Interface,
   /// \brief The "union" keyword.
   TTK_Union,
   /// \brief The "class" keyword.
@@ -3809,6 +3812,8 @@
 enum ElaboratedTypeKeyword {
   /// \brief The "struct" keyword introduces the elaborated-type-specifier.
   ETK_Struct,
+  /// \brief The "__interface" keyword introduces the elaborated-type-specifier.
+  ETK_Interface,
   /// \brief The "union" keyword introduces the elaborated-type-specifier.
   ETK_Union,
   /// \brief The "class" keyword introduces the elaborated-type-specifier.
Index: include/clang/AST/CanonicalType.h
===================================================================
--- include/clang/AST/CanonicalType.h	(revision 162644)
+++ include/clang/AST/CanonicalType.h	(working copy)
@@ -276,6 +276,7 @@
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isMemberFunctionPointerType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isClassType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureType)
+  LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isInterfaceType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isStructureOrClassType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isUnionType)
   LLVM_CLANG_CANPROXY_SIMPLE_ACCESSOR(bool, isComplexIntegerType)
Index: include/clang/AST/DeclCXX.h
===================================================================
--- include/clang/AST/DeclCXX.h	(revision 162644)
+++ include/clang/AST/DeclCXX.h	(working copy)
@@ -1556,7 +1556,9 @@
     CXXMethodDecl *CD =
       cast<CXXMethodDecl>(const_cast<CXXMethodDecl*>(this)->getCanonicalDecl());
 
-    if (CD->isVirtualAsWritten())
+    // methods declared in interfaces are automatically (pure) virtual
+    if (CD->isVirtualAsWritten() ||
+        CD->getParent()->getTagKind() == TTK_Interface)
       return true;
 
     return (CD->begin_overridden_methods() != CD->end_overridden_methods());
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h	(revision 162644)
+++ include/clang/AST/Decl.h	(working copy)
@@ -2448,7 +2448,7 @@
 private:
   // FIXME: This can be packed into the bitfields in Decl.
   /// TagDeclKind - The TagKind enum.
-  unsigned TagDeclKind : 2;
+  unsigned TagDeclKind : 3;
 
   /// IsCompleteDefinition - True if this is a definition ("struct foo
   /// {};"), false if it is a declaration ("struct foo;").  It is not
@@ -2625,6 +2625,7 @@
   void setTagKind(TagKind TK) { TagDeclKind = TK; }
 
   bool isStruct() const { return getTagKind() == TTK_Struct; }
+  bool isInterface() const { return getTagKind() == TTK_Interface; }
   bool isClass()  const { return getTagKind() == TTK_Class; }
   bool isUnion()  const { return getTagKind() == TTK_Union; }
   bool isEnum()   const { return getTagKind() == TTK_Enum; }
Index: include/clang-c/Index.h
===================================================================
--- include/clang-c/Index.h	(revision 162644)
+++ include/clang-c/Index.h	(working copy)
@@ -4965,7 +4965,8 @@
   CXIdxEntity_CXXConstructor        = 22,
   CXIdxEntity_CXXDestructor         = 23,
   CXIdxEntity_CXXConversionFunction = 24,
-  CXIdxEntity_CXXTypeAlias          = 25
+  CXIdxEntity_CXXTypeAlias          = 25,
+  CXIdxEntity_CXXInterface          = 26
 
 } CXIdxEntityKind;
 
Index: tools/libclang/IndexingContext.cpp
===================================================================
--- tools/libclang/IndexingContext.cpp	(revision 162644)
+++ tools/libclang/IndexingContext.cpp	(working copy)
@@ -855,6 +855,10 @@
       EntityInfo.kind = CXIdxEntity_CXXClass;
       EntityInfo.lang = CXIdxEntityLang_CXX;
       break;
+    case TTK_Interface:
+      EntityInfo.kind = CXIdxEntity_CXXInterface;
+      EntityInfo.lang = CXIdxEntityLang_CXX;
+      break;
     case TTK_Enum:
       EntityInfo.kind = CXIdxEntity_Enum; break;
     }
Index: tools/libclang/CIndexUSRs.cpp
===================================================================
--- tools/libclang/CIndexUSRs.cpp	(revision 162644)
+++ tools/libclang/CIndexUSRs.cpp	(working copy)
@@ -402,6 +402,7 @@
       AlreadyStarted = true;
       
       switch (D->getTagKind()) {
+      case TTK_Interface:
       case TTK_Struct: Out << "@ST"; break;
       case TTK_Class:  Out << "@CT"; break;
       case TTK_Union:  Out << "@UT"; break;
@@ -413,6 +414,7 @@
       AlreadyStarted = true;
       
       switch (D->getTagKind()) {
+      case TTK_Interface:
       case TTK_Struct: Out << "@SP"; break;
       case TTK_Class:  Out << "@CP"; break;
       case TTK_Union:  Out << "@UP"; break;
@@ -424,6 +426,7 @@
   
   if (!AlreadyStarted) {
     switch (D->getTagKind()) {
+      case TTK_Interface:
       case TTK_Struct: Out << "@S"; break;
       case TTK_Class:  Out << "@C"; break;
       case TTK_Union:  Out << "@U"; break;
Index: tools/libclang/CIndexCXX.cpp
===================================================================
--- tools/libclang/CIndexCXX.cpp	(revision 162644)
+++ tools/libclang/CIndexCXX.cpp	(working copy)
@@ -67,8 +67,9 @@
           = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(
                                                             getCursorDecl(C))) {
       switch (PartialSpec->getTagKind()) {
+      case TTK_Interface:
+      case TTK_Struct: return CXCursor_StructDecl;
       case TTK_Class: return CXCursor_ClassDecl;
-      case TTK_Struct: return CXCursor_StructDecl;
       case TTK_Union: return CXCursor_UnionDecl;
       case TTK_Enum: return CXCursor_NoDeclFound;
       }
Index: lib/Sema/SemaDeclCXX.cpp
===================================================================
--- lib/Sema/SemaDeclCXX.cpp	(revision 162644)
+++ lib/Sema/SemaDeclCXX.cpp	(working copy)
@@ -675,6 +675,22 @@
   return true;
 }
 
+/// \brief Get diagnostic %select index for tag kind for
+/// record diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getRecordDiagFromTagKind(TagTypeKind Tag)
+{
+  switch (Tag) {
+    case TTK_Struct: return 0;
+    case TTK_Interface: return 1;
+    case TTK_Class:  return 2;
+    default: assert("Invalid tag kind for record diagnostic!");
+  }
+  return -1;
+}
+
 // CheckConstexprFunctionDecl - Check whether a function declaration satisfies
 // the requirements of a constexpr function definition or a constexpr
 // constructor definition. If so, return true. If not, produce appropriate
@@ -691,8 +707,8 @@
     const CXXRecordDecl *RD = MD->getParent();
     if (RD->getNumVBases()) {
       Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base)
-        << isa<CXXConstructorDecl>(NewFD) << RD->isStruct()
-        << RD->getNumVBases();
+        << isa<CXXConstructorDecl>(NewFD)
+        << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
       for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
              E = RD->vbases_end(); I != E; ++I)
         Diag(I->getLocStart(),
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp	(revision 162644)
+++ lib/Sema/SemaExprCXX.cpp	(working copy)
@@ -2998,7 +2998,7 @@
   case UTT_IsUnion:
     return T->isUnionType();
   case UTT_IsClass:
-    return T->isClassType() || T->isStructureType();
+    return T->isClassType() || T->isStructureType() || T->isInterfaceType();
   case UTT_IsFunction:
     return T->isFunctionType();
 
Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp	(revision 162644)
+++ lib/Sema/SemaCodeComplete.cpp	(working copy)
@@ -1059,10 +1059,12 @@
   // Allow us to find class templates, too.
   if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND))
     ND = ClassTemplate->getTemplatedDecl();
-  
+
+  // For purposes of this check, interfaces match too.
   if (RecordDecl *RD = dyn_cast<RecordDecl>(ND))
     return RD->getTagKind() == TTK_Class ||
-    RD->getTagKind() == TTK_Struct;
+    RD->getTagKind() == TTK_Struct ||
+    RD->getTagKind() == TTK_Interface;
   
   return false;
 }
@@ -1422,6 +1424,7 @@
         if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) {
           switch (Tag->getTagKind()) {
           case TTK_Struct: return "struct <anonymous>";
+          case TTK_Interface: return "__interface <anonymous>";
           case TTK_Class:  return "class <anonymous>";            
           case TTK_Union:  return "union <anonymous>";
           case TTK_Enum:   return "enum <anonymous>";
@@ -2884,6 +2887,7 @@
     default:
       if (TagDecl *TD = dyn_cast<TagDecl>(D)) {
         switch (TD->getTagKind()) {
+          case TTK_Interface:  // fall through
           case TTK_Struct: return CXCursor_StructDecl;
           case TTK_Class:  return CXCursor_ClassDecl;
           case TTK_Union:  return CXCursor_UnionDecl;
@@ -3597,6 +3601,7 @@
     
   case DeclSpec::TST_struct:
   case DeclSpec::TST_class:
+  case DeclSpec::TST_interface:
     Filter = &ResultBuilder::IsClassOrStruct;
     ContextKind = CodeCompletionContext::CCC_ClassOrStructTag;
     break;
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp	(revision 162644)
+++ lib/Sema/SemaDecl.cpp	(working copy)
@@ -350,8 +350,8 @@
 /// isTagName() - This method is called *for error recovery purposes only*
 /// to determine if the specified name is a valid tag name ("struct foo").  If
 /// so, this returns the TST for the tag corresponding to it (TST_enum,
-/// TST_union, TST_struct, TST_class).  This is used to diagnose cases in C
-/// where the user forgot to specify the tag.
+/// TST_union, TST_struct, TST_interface, TST_class).  This is used to diagnose
+/// cases in C where the user forgot to specify the tag.
 DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
   // Do a tag name lookup in this scope.
   LookupResult R(*this, &II, SourceLocation(), LookupTagName);
@@ -361,6 +361,7 @@
     if (const TagDecl *TD = R.getAsSingle<TagDecl>()) {
       switch (TD->getTagKind()) {
       case TTK_Struct: return DeclSpec::TST_struct;
+      case TTK_Interface: return DeclSpec::TST_interface;
       case TTK_Union:  return DeclSpec::TST_union;
       case TTK_Class:  return DeclSpec::TST_class;
       case TTK_Enum:   return DeclSpec::TST_enum;
@@ -538,6 +539,11 @@
         FixItTagName = "struct ";
         break;
 
+      case TTK_Interface:
+        TagName = "__interface";
+        FixItTagName = "__interface ";
+        break;
+
       case TTK_Union:
         TagName = "union";
         FixItTagName = "union ";
@@ -2604,6 +2610,7 @@
   TagDecl *Tag = 0;
   if (DS.getTypeSpecType() == DeclSpec::TST_class ||
       DS.getTypeSpecType() == DeclSpec::TST_struct ||
+      DS.getTypeSpecType() == DeclSpec::TST_interface ||
       DS.getTypeSpecType() == DeclSpec::TST_union ||
       DS.getTypeSpecType() == DeclSpec::TST_enum) {
     TagD = DS.getRepAsDecl();
@@ -2642,7 +2649,8 @@
       Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag)
         << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 :
             DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 :
-            DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3);
+            DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 :
+            DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4);
     else
       Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators);
     // Don't emit warnings after this error.
@@ -2763,6 +2771,7 @@
     DeclSpec::TST TypeSpecType = DS.getTypeSpecType();
     if (TypeSpecType == DeclSpec::TST_class ||
         TypeSpecType == DeclSpec::TST_struct ||
+        TypeSpecType == DeclSpec::TST_interface ||
         TypeSpecType == DeclSpec::TST_union ||
         TypeSpecType == DeclSpec::TST_enum) {
       AttributeList* attrs = DS.getAttributes().getList();
@@ -2772,7 +2781,8 @@
         << attrs->getName()
         << (TypeSpecType == DeclSpec::TST_class ? 0 :
             TypeSpecType == DeclSpec::TST_struct ? 1 :
-            TypeSpecType == DeclSpec::TST_union ? 2 : 3);
+            TypeSpecType == DeclSpec::TST_union ? 2 :
+            TypeSpecType == DeclSpec::TST_interface ? 3 : 4);
         attrs = attrs->getNext();
       }
     }
@@ -5177,6 +5187,14 @@
       NewFD->setImplicitlyInline();
     }
 
+    // if this is a method defined in an __interface, set pure
+    // (isVirtual will already return true)
+    if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>(
+        NewFD->getDeclContext())) {
+      if (Parent->getTagKind() == TTK_Interface)
+        NewFD->setPure(true);
+    }
+
     SetNestedNameSpecifier(NewFD, D);
     isExplicitSpecialization = false;
     isFunctionTemplateSpecialization = false;
@@ -8110,6 +8128,7 @@
   switch (D.getDeclSpec().getTypeSpecType()) {
   case TST_enum:
   case TST_struct:
+  case TST_interface:
   case TST_union:
   case TST_class: {
     TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl());
@@ -8185,6 +8204,31 @@
   return false;
 }
 
+/// \brief Get diagnostic %select index for tag kind for
+/// redeclaration diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag)
+{
+  switch (Tag) {
+    case TTK_Struct: return 0;
+    case TTK_Interface: return 1;
+    case TTK_Class:  return 2;
+    default: assert("Invalid tag kind for redecl diagnostic!");
+  }
+  return -1;
+}
+
+/// \brief Determine if tag kind is a class-key compatible with
+/// class for redeclaration (class, struct, or __interface).
+///
+/// \returns true iff the tag kind is compatible.
+static bool isClassCompatTagKind(TagTypeKind Tag)
+{
+  return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface;
+}
+
 /// \brief Determine whether a tag with a given kind is acceptable
 /// as a redeclaration of the given tag declaration.
 ///
@@ -8207,12 +8251,11 @@
   //   struct class-key shall be used to refer to a class (clause 9)
   //   declared using the class or struct class-key.
   TagTypeKind OldTag = Previous->getTagKind();
-  if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct))
+  if (!isDefinition || !isClassCompatTagKind(NewTag))
     if (OldTag == NewTag)
       return true;
 
-  if ((OldTag == TTK_Struct || OldTag == TTK_Class) &&
-      (NewTag == TTK_Struct || NewTag == TTK_Class)) {
+  if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) {
     // Warn about the struct/class tag mismatch.
     bool isTemplate = false;
     if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous))
@@ -8222,7 +8265,8 @@
       // In a template instantiation, do not offer fix-its for tag mismatches
       // since they usually mess up the template instead of fixing the problem.
       Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
-        << (NewTag == TTK_Class) << isTemplate << &Name;
+        << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+        << getRedeclDiagFromTagKind(OldTag);
       return true;
     }
 
@@ -8241,13 +8285,13 @@
           if (!previousMismatch) {
             previousMismatch = true;
             Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch)
-              << (NewTag == TTK_Class) << isTemplate << &Name;
+              << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+              << getRedeclDiagFromTagKind(I->getTagKind());
           }
           Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion)
-            << (NewTag == TTK_Class)
+            << getRedeclDiagFromTagKind(NewTag)
             << FixItHint::CreateReplacement(I->getInnerLocStart(),
-                                            NewTag == TTK_Class?
-                                            "class" : "struct");
+                 TypeWithKeyword::getTagTypeKindName(NewTag));
         }
       }
       return true;
@@ -8263,16 +8307,16 @@
     }
 
     Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch)
-      << (NewTag == TTK_Class)
-      << isTemplate << &Name;
+      << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name
+      << getRedeclDiagFromTagKind(OldTag);
     Diag(Redecl->getLocation(), diag::note_previous_use);
 
     // If there is a previous defintion, suggest a fix-it.
     if (Previous->getDefinition()) {
         Diag(NewTagLoc, diag::note_struct_class_suggestion)
-          << (Redecl->getTagKind() == TTK_Class)
+          << getRedeclDiagFromTagKind(Redecl->getTagKind())
           << FixItHint::CreateReplacement(SourceRange(NewTagLoc),
-                        Redecl->getTagKind() == TTK_Class? "class" : "struct");
+               TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind()));
     }
 
     return true;
Index: lib/Sema/DeclSpec.cpp
===================================================================
--- lib/Sema/DeclSpec.cpp	(revision 162644)
+++ lib/Sema/DeclSpec.cpp	(working copy)
@@ -270,6 +270,7 @@
     case TST_int:
     case TST_int128:
     case TST_struct:
+    case TST_interface:
     case TST_union:
     case TST_unknown_anytype:
     case TST_unspecified:
@@ -396,6 +397,7 @@
   case DeclSpec::TST_class:       return "class";
   case DeclSpec::TST_union:       return "union";
   case DeclSpec::TST_struct:      return "struct";
+  case DeclSpec::TST_interface:   return "__interface";
   case DeclSpec::TST_typename:    return "type-name";
   case DeclSpec::TST_typeofType:
   case DeclSpec::TST_typeofExpr:  return "typeof";
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp	(revision 162644)
+++ lib/Sema/SemaType.cpp	(working copy)
@@ -753,7 +753,8 @@
   case DeclSpec::TST_class:
   case DeclSpec::TST_enum:
   case DeclSpec::TST_union:
-  case DeclSpec::TST_struct: {
+  case DeclSpec::TST_struct:
+  case DeclSpec::TST_interface: {
     TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl());
     if (!D) {
       // This can happen in C++ with ambiguous lookups.
@@ -1853,30 +1854,31 @@
       case TTK_Struct: Error = 1; /* Struct member */ break;
       case TTK_Union:  Error = 2; /* Union member */ break;
       case TTK_Class:  Error = 3; /* Class member */ break;
+      case TTK_Interface: Error = 4; /* Interface member */ break;
       }
       break;
     case Declarator::CXXCatchContext:
     case Declarator::ObjCCatchContext:
-      Error = 4; // Exception declaration
+      Error = 5; // Exception declaration
       break;
     case Declarator::TemplateParamContext:
-      Error = 5; // Template parameter
+      Error = 6; // Template parameter
       break;
     case Declarator::BlockLiteralContext:
-      Error = 6; // Block literal
+      Error = 7; // Block literal
       break;
     case Declarator::TemplateTypeArgContext:
-      Error = 7; // Template type argument
+      Error = 8; // Template type argument
       break;
     case Declarator::AliasDeclContext:
     case Declarator::AliasTemplateContext:
-      Error = 9; // Type alias
+      Error = 10; // Type alias
       break;
     case Declarator::TrailingReturnContext:
-      Error = 10; // Function return type
+      Error = 11; // Function return type
       break;
     case Declarator::TypeNameContext:
-      Error = 11; // Generic
+      Error = 12; // Generic
       break;
     case Declarator::FileContext:
     case Declarator::BlockContext:
@@ -1887,11 +1889,11 @@
     }
 
     if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef)
-      Error = 8;
+      Error = 9;
 
     // In Objective-C it is an error to use 'auto' on a function declarator.
     if (D.isFunctionDeclarator())
-      Error = 10;
+      Error = 11;
 
     // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator
     // contains a trailing return type. That is only legal at the outermost
@@ -4430,6 +4432,22 @@
   return RequireCompleteType(Loc, T, Diagnoser);
 }
 
+/// \brief Get diagnostic %select index for tag kind for
+/// literal type diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag)
+{
+  switch (Tag) {
+    case TTK_Struct: return 0;
+    case TTK_Interface: return 1;
+    case TTK_Class:  return 2;
+    default: assert("Invalid tag kind for literal type diagnostic!");
+  }
+  return -1;
+}
+
 /// @brief Ensure that the type T is a literal type.
 ///
 /// This routine checks whether the type @p T is a literal type. If @p T is an
@@ -4486,7 +4504,7 @@
   // of constexpr constructors.
   if (RD->getNumVBases()) {
     Diag(RD->getLocation(), diag::note_non_literal_virtual_base)
-      << RD->isStruct() << RD->getNumVBases();
+      << getLiteralDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases();
     for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(),
            E = RD->vbases_end(); I != E; ++I)
       Diag(I->getLocStart(),
Index: lib/Sema/SemaTemplateVariadic.cpp
===================================================================
--- lib/Sema/SemaTemplateVariadic.cpp	(revision 162644)
+++ lib/Sema/SemaTemplateVariadic.cpp	(working copy)
@@ -727,6 +727,7 @@
   case TST_enum:
   case TST_union:
   case TST_struct:
+  case TST_interface:
   case TST_class:
   case TST_auto:
   case TST_unknown_anytype:
Index: lib/AST/Type.cpp
===================================================================
--- lib/AST/Type.cpp	(revision 162644)
+++ lib/AST/Type.cpp	(working copy)
@@ -357,9 +357,15 @@
     return RT->getDecl()->isStruct();
   return false;
 }
+bool Type::isInterfaceType() const {
+  if (const RecordType *RT = getAs<RecordType>())
+    return RT->getDecl()->isInterface();
+  return false;
+}
 bool Type::isStructureOrClassType() const {
   if (const RecordType *RT = getAs<RecordType>())
-    return RT->getDecl()->isStruct() || RT->getDecl()->isClass();
+    return RT->getDecl()->isStruct() || RT->getDecl()->isClass() ||
+      RT->getDecl()->isInterface();
   return false;
 }
 bool Type::isVoidPointerType() const {
@@ -1317,6 +1323,7 @@
   case TST_typename: return ETK_Typename;
   case TST_class: return ETK_Class;
   case TST_struct: return ETK_Struct;
+  case TST_interface: return ETK_Interface;
   case TST_union: return ETK_Union;
   case TST_enum: return ETK_Enum;
   }
@@ -1327,6 +1334,7 @@
   switch(TypeSpec) {
   case TST_class: return TTK_Class;
   case TST_struct: return TTK_Struct;
+  case TST_interface: return TTK_Interface;
   case TST_union: return TTK_Union;
   case TST_enum: return TTK_Enum;
   }
@@ -1339,6 +1347,7 @@
   switch (Kind) {
   case TTK_Class: return ETK_Class;
   case TTK_Struct: return ETK_Struct;
+  case TTK_Interface: return ETK_Interface;
   case TTK_Union: return ETK_Union;
   case TTK_Enum: return ETK_Enum;
   }
@@ -1350,6 +1359,7 @@
   switch (Keyword) {
   case ETK_Class: return TTK_Class;
   case ETK_Struct: return TTK_Struct;
+  case ETK_Interface: return TTK_Interface;
   case ETK_Union: return TTK_Union;
   case ETK_Enum: return TTK_Enum;
   case ETK_None: // Fall through.
@@ -1367,6 +1377,7 @@
     return false;
   case ETK_Class:
   case ETK_Struct:
+  case ETK_Interface:
   case ETK_Union:
   case ETK_Enum:
     return true;
@@ -1381,6 +1392,7 @@
   case ETK_Typename: return "typename";
   case ETK_Class:  return "class";
   case ETK_Struct: return "struct";
+  case ETK_Interface: return "__interface";
   case ETK_Union:  return "union";
   case ETK_Enum:   return "enum";
   }
Index: lib/AST/RecordLayoutBuilder.cpp
===================================================================
--- lib/AST/RecordLayoutBuilder.cpp	(revision 162644)
+++ lib/AST/RecordLayoutBuilder.cpp	(working copy)
@@ -2263,6 +2263,22 @@
   return ExternalFieldOffset;
 }
 
+/// \brief Get diagnostic %select index for tag kind for
+/// field padding diagnostic message.
+/// WARNING: Indexes apply to particular diagnostics only!
+///
+/// \returns diagnostic %select index.
+static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag)
+{
+  switch (Tag) {
+    case TTK_Struct: return 0;
+    case TTK_Interface: return 1;
+    case TTK_Class:  return 2;
+    default: assert("Invalid tag kind for field padding diagnostic!");
+  }
+  return -1;
+}
+
 void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset,
                                             uint64_t UnpaddedOffset,
                                             uint64_t UnpackedOffset,
@@ -2291,14 +2307,14 @@
     }
     if (D->getIdentifier())
       Diag(D->getLocation(), diag::warn_padded_struct_field)
-          << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+          << getPaddingDiagFromTagKind(D->getParent()->getTagKind())
           << Context.getTypeDeclType(D->getParent())
           << PadSize
           << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not
           << D->getIdentifier();
     else
       Diag(D->getLocation(), diag::warn_padded_struct_anon_field)
-          << (D->getParent()->isStruct() ? 0 : 1) // struct|class
+          << getPaddingDiagFromTagKind(D->getParent()->getTagKind())
           << Context.getTypeDeclType(D->getParent())
           << PadSize
           << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp	(revision 162644)
+++ lib/AST/MicrosoftMangle.cpp	(working copy)
@@ -1273,6 +1273,7 @@
       Out << 'T';
       break;
     case TTK_Struct:
+    case TTK_Interface:
       Out << 'U';
       break;
     case TTK_Class:
Index: lib/AST/DeclCXX.cpp
===================================================================
--- lib/AST/DeclCXX.cpp	(revision 162644)
+++ lib/AST/DeclCXX.cpp	(working copy)
@@ -466,7 +466,8 @@
   if (!D->isImplicit() &&
       !isa<FieldDecl>(D) &&
       !isa<IndirectFieldDecl>(D) &&
-      (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class))
+      (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class ||
+        cast<TagDecl>(D)->getTagKind() == TTK_Interface))
     data().HasOnlyCMembers = false;
 
   // Ignore friends and invalid declarations.
@@ -936,7 +937,8 @@
 }
 
 bool CXXRecordDecl::isCLike() const {
-  if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull())
+  if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface ||
+      !TemplateOrInstantiation.isNull())
     return false;
   if (!hasDefinition())
     return true;
Index: lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- lib/CodeGen/CGDebugInfo.cpp	(revision 162644)
+++ lib/CodeGen/CGDebugInfo.cpp	(working copy)
@@ -523,7 +523,7 @@
     RDName = getClassName(RD);
     Tag = llvm::dwarf::DW_TAG_class_type;
   }
-  else if (RD->isStruct())
+  else if (RD->isStruct() || RD->isInterface())
     Tag = llvm::dwarf::DW_TAG_structure_type;
   else if (RD->isUnion())
     Tag = llvm::dwarf::DW_TAG_union_type;
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp	(revision 162644)
+++ lib/Parse/ParseDecl.cpp	(working copy)
@@ -1875,6 +1875,9 @@
         TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break;
       case DeclSpec::TST_struct:
         TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break;
+      case DeclSpec::TST_interface:
+        TagName="__interface"; FixitTagName = "__interface ";
+        TagKind=tok::kw___interface;break;
       case DeclSpec::TST_class:
         TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break;
     }
@@ -2709,6 +2712,7 @@
     // class-specifier:
     case tok::kw_class:
     case tok::kw_struct:
+    case tok::kw___interface:
     case tok::kw_union: {
       tok::TokenKind Kind = Tok.getKind();
       ConsumeToken();
@@ -3531,6 +3535,7 @@
     // struct-or-union-specifier (C99) or class-specifier (C++)
   case tok::kw_class:
   case tok::kw_struct:
+  case tok::kw___interface:
   case tok::kw_union:
     // enum-specifier
   case tok::kw_enum:
@@ -3602,6 +3607,7 @@
     // struct-or-union-specifier (C99) or class-specifier (C++)
   case tok::kw_class:
   case tok::kw_struct:
+  case tok::kw___interface:
   case tok::kw_union:
     // enum-specifier
   case tok::kw_enum:
@@ -3740,6 +3746,7 @@
   case tok::kw_class:
   case tok::kw_struct:
   case tok::kw_union:
+  case tok::kw___interface:
     // enum-specifier
   case tok::kw_enum:
 
Index: lib/Parse/ParseDeclCXX.cpp
===================================================================
--- lib/Parse/ParseDeclCXX.cpp	(revision 162644)
+++ lib/Parse/ParseDeclCXX.cpp	(working copy)
@@ -1034,6 +1034,8 @@
   DeclSpec::TST TagType;
   if (TagTokKind == tok::kw_struct)
     TagType = DeclSpec::TST_struct;
+  else if (TagTokKind == tok::kw___interface)
+    TagType = DeclSpec::TST_interface;
   else if (TagTokKind == tok::kw_class)
     TagType = DeclSpec::TST_class;
   else {
@@ -1151,7 +1153,8 @@
         << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation)
         << (TagType == DeclSpec::TST_class? 0
             : TagType == DeclSpec::TST_struct? 1
-            : 2)
+            : TagType == DeclSpec::TST_interface? 2
+            : 3)
         << Name
         << SourceRange(LAngleLoc, RAngleLoc);
 
@@ -1243,8 +1246,7 @@
     if (Tok.isNot(tok::semi)) {
       // A semicolon was missing after this declaration. Diagnose and recover.
       ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
-                       TagType == DeclSpec::TST_class ? "class" :
-                       TagType == DeclSpec::TST_struct ? "struct" : "union");
+        DeclSpec::getSpecifierName(TagType));
       PP.EnterToken(Tok);
       Tok.setKind(tok::semi);
     }
@@ -1469,8 +1471,7 @@
   if (TUK == Sema::TUK_Definition &&
       (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) {
     ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl,
-                     TagType == DeclSpec::TST_class ? "class" :
-                     TagType == DeclSpec::TST_struct ? "struct" : "union");
+      DeclSpec::getSpecifierName(TagType));
     // Push this token back into the preprocessor and change our current token
     // to ';' so that the rest of the code recovers as though there were an
     // ';' after the definition.
@@ -2239,6 +2240,7 @@
 void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
                                          unsigned TagType, Decl *TagDecl) {
   assert((TagType == DeclSpec::TST_struct ||
+         TagType == DeclSpec::TST_interface ||
          TagType == DeclSpec::TST_union  ||
          TagType == DeclSpec::TST_class) && "Invalid TagType!");
 
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp	(revision 162644)
+++ lib/Serialization/ASTReaderDecl.cpp	(working copy)
@@ -1719,8 +1719,10 @@
   if (TagDecl *TagX = dyn_cast<TagDecl>(X)) {
     TagDecl *TagY = cast<TagDecl>(Y);
     return (TagX->getTagKind() == TagY->getTagKind()) ||
-      ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) &&
-       (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class));
+      ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class ||
+        TagX->getTagKind() == TTK_Interface) &&
+       (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class ||
+        TagY->getTagKind() == TTK_Interface));
   }
   
   // Functions with the same type and linkage match.


More information about the cfe-dev mailing list