[cfe-dev] [PATCH] Improve __interface support
David Robins
llvm at davidrobins.net
Sat Aug 18 07:57:36 PDT 2012
On Sat, Aug 18, 2012 at 08:58:08AM +0100, João Matos wrote:
> Hi, nice patch.
>
> NewFD->setVirtualAsWritten(true);
>
> Do we need to set this on the method? According to the docs, this should
> only be set if virtual was explicitly written in the code.
I don't know how else to set it. __interface implies all member
functions defined within are pure virtual, so one could say "as written"
fits the user writing "__interface" to get virtual functions. If there's
a better way to set virtual, I'll use it.
> - if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct))
> - if (OldTag == NewTag)
> - return true;
> + if (!isDefinition || !isClassCompatTagKind(NewTag) || OldTag == NewTag)
> + return true;
>
> The behaviour of the code is changed here, though I'm not sure if that has
> any impact on correctness.
It does - I must have not updated the patch after the last update I
made. In the later one this code is back to as it was except for adding
handling for __interface. [Oops. Grabbed the patch from the wrong
machine. Newer one is attached.]
> + default: assert("Invalid tag kind for field padding diagnostic!");
>
> You used this assert message on a couple diagnostic index helper functions
> which is incorrect for some. Seems to be a simple copy paste mismatch.
This is also taken care of in the attached update.
> + case TTK_Interface:
> Out << 'U';
>
> Did you confirm that cl mangles interfaces as structs?
Yes.
> + case TTK_Interface:
> + case TTK_Struct: return CXCursor_StructDecl;
>
> I think we should add a new cursor in the C API, and not re-use
> CXCursor_StructDecl for interfaces.
See previous message to list ("CXCursor value for __interface"): since
the cursor values are part of a public interface, I didn't think I could
change the values to insert an interface cursor; and there is no space
between CXCursor_LastDecl and CXCursor_FirstRef to add anything without
doing that. John McCall replied and said he thought using StructDecl was
fine.
-------------- next part --------------
Index: test/Parser/MicrosoftExtensions.cpp
===================================================================
--- test/Parser/MicrosoftExtensions.cpp (revision 161741)
+++ 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 161741)
+++ 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 161741)
+++ 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 161741)
+++ include/clang/Basic/DiagnosticParseKinds.td (working copy)
@@ -570,7 +570,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 161741)
+++ 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 161741)
+++ 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<
@@ -1300,9 +1301,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<
@@ -1420,7 +1422,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">;
@@ -1438,11 +1440,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">;
@@ -1672,7 +1675,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>;
@@ -3151,8 +3156,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">;
@@ -3160,15 +3165,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<
@@ -3212,11 +3218,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;
@@ -3464,14 +3472,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>;
@@ -4550,7 +4560,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">;
@@ -5879,7 +5889,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 161741)
+++ 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 161741)
+++ 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 161741)
+++ 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/Decl.h
===================================================================
--- include/clang/AST/Decl.h (revision 161741)
+++ 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 161741)
+++ 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 161741)
+++ 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 161741)
+++ 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 161741)
+++ 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 161741)
+++ lib/Sema/SemaDeclCXX.cpp (working copy)
@@ -676,6 +676,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
@@ -692,8 +708,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 161741)
+++ lib/Sema/SemaExprCXX.cpp (working copy)
@@ -3007,7 +3007,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 161741)
+++ 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 161741)
+++ 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 ";
@@ -2565,6 +2571,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();
@@ -2603,7 +2610,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.
@@ -2724,6 +2732,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();
@@ -2733,7 +2742,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();
}
}
@@ -5138,6 +5148,15 @@
NewFD->setImplicitlyInline();
}
+ // if this is a method defined in an __interface, set pure virtual
+ if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>(
+ NewFD->getDeclContext())) {
+ if (Parent->getTagKind() == TTK_Interface) {
+ NewFD->setVirtualAsWritten(true);
+ NewFD->setPure(true);
+ }
+ }
+
SetNestedNameSpecifier(NewFD, D);
isExplicitSpecialization = false;
isFunctionTemplateSpecialization = false;
@@ -8025,6 +8044,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());
@@ -8100,6 +8120,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.
///
@@ -8122,12 +8167,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))
@@ -8137,7 +8181,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;
}
@@ -8156,13 +8201,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;
@@ -8178,16 +8223,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 161741)
+++ 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 161741)
+++ 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
@@ -4385,6 +4387,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
@@ -4441,7 +4459,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 161741)
+++ 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 161741)
+++ 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 161741)
+++ 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 161741)
+++ lib/AST/MicrosoftMangle.cpp (working copy)
@@ -1271,6 +1271,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 161741)
+++ 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 161741)
+++ lib/CodeGen/CGDebugInfo.cpp (working copy)
@@ -505,7 +505,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 161741)
+++ lib/Parse/ParseDecl.cpp (working copy)
@@ -1803,6 +1803,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;
}
@@ -2637,6 +2640,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();
@@ -3457,6 +3461,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:
@@ -3528,6 +3533,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:
@@ -3666,6 +3672,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 161741)
+++ 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);
}
@@ -1470,8 +1472,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.
@@ -2240,6 +2241,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 161741)
+++ 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