vsapsai updated this revision to Diff 425093.
vsapsai added a comment.
Rebase and update test to use `ptr` instead of `i64*`. Also now the added test
is failing for `implementationIvar`, investigating that.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D121177/new/
https://reviews.llvm.org/D121177
Files:
clang/include/clang/AST/DeclObjC.h
clang/include/clang/Serialization/ASTReader.h
clang/lib/AST/DeclObjC.cpp
clang/lib/Serialization/ASTReader.cpp
clang/lib/Serialization/ASTReaderDecl.cpp
clang/test/Modules/merge-extension-ivars.m
clang/test/Modules/redecl-ivars.m
Index: clang/test/Modules/redecl-ivars.m
===================================================================
--- /dev/null
+++ clang/test/Modules/redecl-ivars.m
@@ -0,0 +1,166 @@
+// UNSUPPORTED: -zos, -aix
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-mismatch-in-extension.m
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-mismatch-in-extension.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-mismatch-in-ivars-number.m
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-mismatch-in-ivars-number.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-mismatch-in-methods-protocols.m
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-mismatch-in-methods-protocols.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-redecl-in-subclass.m
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-redecl-in-subclass.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-redecl-in-implementation.m
+// RUN: %clang_cc1 -fsyntax-only -fobjc-runtime=macosx-10.9 -verify -I%t/include %t/test-redecl-in-implementation.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+
+// Same class extensions with the same ivars but from different modules aren't considered
+// an error and they are merged together. Test that differences in extensions and/or ivars
+// are still reported as errors.
+
+//--- include/Interfaces.h
+@interface NSObject @end
+@interface ObjCInterface : NSObject
+@end
+@interface ObjCInterfaceLevel2 : ObjCInterface
+@end
+
+@protocol Protocol1 @end
+@protocol Protocol2 @end
+
+//--- include/IvarsInExtensions.h
+#import <Interfaces.h>
+@interface ObjCInterface() {
+ int ivarName;
+}
+@end
+@interface ObjCInterfaceLevel2() {
+ int bitfieldIvarName: 3;
+}
+@end
+
+//--- include/IvarsInExtensionsWithMethodsProtocols.h
+#import <Interfaces.h>
+@interface ObjCInterface() {
+ int methodRelatedIvar;
+}
+- (void)test;
+@end
+@interface ObjCInterfaceLevel2() <Protocol1> {
+ int protocolRelatedIvar;
+}
+@end
+
+//--- include/IvarInImplementation.h
+#import <Interfaces.h>
+@implementation ObjCInterface {
+ int ivarName;
+}
+@end
+
+//--- include/module.modulemap
+module Interfaces {
+ header "Interfaces.h"
+ export *
+}
+module IvarsInExtensions {
+ header "IvarsInExtensions.h"
+ export *
+}
+module IvarsInExtensionsWithMethodsProtocols {
+ header "IvarsInExtensionsWithMethodsProtocols.h"
+ export *
+}
+module IvarInImplementation {
+ header "IvarInImplementation.h"
+ export *
+}
+
+
+//--- test-mismatch-in-extension.m
+// Different ivars with the same name aren't mergeable and constitute an error.
+#import <Interfaces.h>
+@interface ObjCInterface() {
+ float ivarName; // expected-note {{previous definition is here}}
+}
+@end
+@interface ObjCInterfaceLevel2() {
+ int bitfieldIvarName: 5; // expected-note {{previous definition is here}}
+}
+@end
+#import <IvarsInExtensions.h>
+// [email protected]:* {{instance variable is already declared}}
+// [email protected]:* {{instance variable is already declared}}
+@implementation ObjCInterfaceLevel2
+@end
+
+
+//--- test-mismatch-in-ivars-number.m
+// Extensions with different amount of ivars aren't considered to be the same.
+#import <Interfaces.h>
+@interface ObjCInterface() {
+ int ivarName; // expected-note {{previous definition is here}}
+ float anotherIvar;
+}
+@end
+#import <IvarsInExtensions.h>
+// [email protected]:* {{instance variable is already declared}}
+@implementation ObjCInterface
+@end
+
+
+//--- test-mismatch-in-methods-protocols.m
+// Extensions with different methods or protocols aren't considered to be the same.
+#import <Interfaces.h>
+@interface ObjCInterface() {
+ int methodRelatedIvar; // expected-note {{previous definition is here}}
+}
+- (void)differentTest;
+@end
+@interface ObjCInterfaceLevel2() <Protocol2> {
+ int protocolRelatedIvar; // expected-note {{previous definition is here}}
+}
+@end
+#import <IvarsInExtensionsWithMethodsProtocols.h>
+// [email protected]:* {{instance variable is already declared}}
+// [email protected]:* {{instance variable is already declared}}
+@implementation ObjCInterfaceLevel2
+@end
+
+
+//--- test-redecl-in-subclass.m
+// Ivar in superclass extension is not added to a subclass, so the ivar with
+// the same name in subclass extension is not considered a redeclaration.
+// expected-no-diagnostics
+#import <Interfaces.h>
+@interface ObjCInterfaceLevel2() {
+ float ivarName;
+}
+@end
+#import <IvarsInExtensions.h>
+@implementation ObjCInterfaceLevel2
+@end
+
+
+//--- test-redecl-in-implementation.m
+// Ivar redeclaration in `@implementation` is always an error and never mergeable.
+#import <IvarsInExtensions.h>
+@interface ObjCInterface() {
+ int triggerExtensionIvarDeserialization;
+}
+@end
+#import <IvarInImplementation.h>
+#if __has_feature(modules)
+// [email protected]:* {{instance variable is already declared}}
+// [email protected]:* {{previous definition is here}}
+#else
+// [email protected]:* {{instance variable is already declared}}
+// [email protected]:* {{previous definition is here}}
+#endif
Index: clang/test/Modules/merge-extension-ivars.m
===================================================================
--- /dev/null
+++ clang/test/Modules/merge-extension-ivars.m
@@ -0,0 +1,146 @@
+// UNSUPPORTED: -zos, -aix
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: %clang_cc1 -emit-llvm -o %t/test-compatible-extensions.ll -fobjc-runtime=macosx-10.9 -F%t/Frameworks %t/test-compatible-extensions.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache -fmodule-name=InterfaceAndExtension
+// RUN: FileCheck --input-file=%t/test-compatible-extensions.ll %t/test-compatible-extensions.m
+
+// RUN: %clang_cc1 -emit-llvm -o %t/test-access-extension-ivar.ll -fobjc-runtime=macosx-10.9 -F%t/Frameworks %t/test-access-extension-ivar.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+// RUN: FileCheck --input-file=%t/test-access-extension-ivar.ll %t/test-access-extension-ivar.m
+
+// RUN: %clang_cc1 -emit-llvm -o %t/test-synthesized-ivar.ll -fobjc-runtime=macosx-10.9 -F%t/Frameworks %t/test-synthesized-ivar.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache
+// RUN: FileCheck --input-file=%t/test-synthesized-ivar.ll %t/test-synthesized-ivar.m
+// RUN: %clang_cc1 -emit-llvm -o %t/test-synthesized-ivar-extension.ll -fobjc-runtime=macosx-10.9 -F%t/Frameworks %t/test-synthesized-ivar.m \
+// RUN: -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/modules.cache \
+// RUN: -DIMPORT_EXTENSION=1
+// RUN: FileCheck --input-file=%t/test-synthesized-ivar-extension.ll %t/test-synthesized-ivar.m
+
+// Test various scenarios where we can end up with the same-name ivars coming from multiple modules.
+// The goal is to avoid duplicate metadata for ivars because it can lead to miscompilations
+// with a wrong ivar offset.
+//
+// See specific .m tests for the details of various scenarios.
+
+//--- Frameworks/InterfaceAndExtension.framework/Headers/Interface.h
+@interface NSObject @end
+@interface ObjCInterface : NSObject
+@end
+
+//--- Frameworks/InterfaceAndExtension.framework/Headers/Extension.h
+#import <InterfaceAndExtension/Interface.h>
+@interface ObjCInterface() {
+ float ivarInExtension;
+ int bitfieldIvarInExtension: 3;
+}
+@end
+
+//--- Frameworks/InterfaceAndExtension.framework/Headers/InterfaceAndExtension.h
+#import <InterfaceAndExtension/Interface.h>
+#import <InterfaceAndExtension/Extension.h>
+
+//--- Frameworks/InterfaceAndExtension.framework/Modules/module.modulemap
+framework module InterfaceAndExtension {
+ umbrella header "InterfaceAndExtension.h"
+ export *
+ module * { export * }
+}
+
+//--- Frameworks/Redirecting.framework/Headers/Redirecting.h
+#import <InterfaceAndExtension/InterfaceAndExtension.h>
+
+//--- Frameworks/Redirecting.framework/Modules/module.modulemap
+framework module Redirecting {
+ header "Redirecting.h"
+ export *
+}
+
+//--- test-compatible-extensions.m
+// Test adding through deserialization an extension with already declared ivars.
+
+// First create `ObjCInterface()` extension by parsing corresponding code.
+#import <InterfaceAndExtension/InterfaceAndExtension.h>
+// Now add the same extension through deserialization from the imported module.
+#import <Redirecting/Redirecting.h>
+@implementation ObjCInterface {
+ int ivarInImplementation;
+}
+@end
+// CHECK: @"_OBJC_$_INSTANCE_VARIABLES_ObjCInterface"
+// CHECK-SAME: [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_ObjCInterface.ivarInExtension", {{.*}} }, %struct._ivar_t { ptr @"OBJC_IVAR_$_ObjCInterface.bitfieldIvarInExtension", {{.*}} }, %struct._ivar_t { ptr @"OBJC_IVAR_$_ObjCInterface.ivarInImplementation", {{.*}} }]
+
+
+//--- Frameworks/WithInlineIvar.framework/Headers/WithInlineIvar.h
+#import <InterfaceAndExtension/InterfaceAndExtension.h>
+@interface ObjCInterface() {
+@public
+ int accessedIvar;
+}
+@end
+static inline void inlinedIvarAccessor(ObjCInterface *obj) {
+ obj->accessedIvar = 0;
+}
+
+//--- Frameworks/WithInlineIvar.framework/Modules/module.modulemap
+framework module WithInlineIvar {
+ header "WithInlineIvar.h"
+ export *
+}
+
+//--- test-access-extension-ivar.m
+// Test accessing ivars from extensions.
+#import <InterfaceAndExtension/InterfaceAndExtension.h>
+@interface ObjCInterface() {
+@public
+ int accessedIvar;
+}
+@end
+#import <WithInlineIvar/WithInlineIvar.h>
+@implementation ObjCInterface
+- (void)test {
+ inlinedIvarAccessor(self);
+ ivarInExtension = 0;
+}
+@end
+// CHECK: @"_OBJC_$_INSTANCE_VARIABLES_ObjCInterface"
+// CHECK-SAME: [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_ObjCInterface.accessedIvar", {{.*}} }, %struct._ivar_t { ptr @"OBJC_IVAR_$_ObjCInterface.ivarInExtension", {{.*}} }, %struct._ivar_t { ptr @"OBJC_IVAR_$_ObjCInterface.bitfieldIvarInExtension", {{.*}} }]
+
+
+//--- Frameworks/WithProperty.framework/Headers/WithProperty.h
+@interface NSObject @end
+@interface WithProperty: NSObject
+@property (assign) int propertyName;
+@end
+
+//--- Frameworks/WithProperty.framework/Modules/module.modulemap
+framework module WithProperty {
+ header "WithProperty.h"
+ export *
+}
+
+//--- Frameworks/BackingIvarInExtension.framework/Headers/BackingIvarInExtension.h
+#import <WithProperty/WithProperty.h>
+@interface WithProperty() {
+ int propertyBackingIvar;
+}
+@end
+
+//--- Frameworks/BackingIvarInExtension.framework/Modules/module.modulemap
+framework module BackingIvarInExtension {
+ header "BackingIvarInExtension.h"
+ export *
+}
+
+//--- test-synthesized-ivar.m
+// Test when an ivar is both synthesized and when declared in an extension.
+// Behavior with and without extension should be the same.
+#import <WithProperty/WithProperty.h>
+#ifdef IMPORT_EXTENSION
+#import <BackingIvarInExtension/BackingIvarInExtension.h>
+#endif
+@implementation WithProperty
+@synthesize propertyName = propertyBackingIvar;
+@end
+// CHECK: @"_OBJC_$_INSTANCE_VARIABLES_WithProperty"
+// CHECK-SAME: [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_WithProperty.propertyBackingIvar", {{.*}} }]
Index: clang/lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderDecl.cpp
+++ clang/lib/Serialization/ASTReaderDecl.cpp
@@ -36,6 +36,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/UnresolvedSet.h"
#include "clang/Basic/AttrKinds.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
@@ -1232,6 +1233,36 @@
IVD->setNextIvar(nullptr);
bool synth = Record.readInt();
IVD->setSynthesize(synth);
+
+ // Check ivar redeclaration.
+ if (IVD->isInvalidDecl())
+ return;
+ // Don't check ObjCInterfaceDecl as interfaces are named and mismatches can be
+ // detected in VisitObjCInterfaceDecl. Here we are interested in finding
+ // redeclarations mostly in extensions.
+ if (isa<ObjCInterfaceDecl>(IVD->getDeclContext()))
+ return;
+ ObjCInterfaceDecl *CanonIntf =
+ IVD->getContainingInterface()->getCanonicalDecl();
+ IdentifierInfo *II = IVD->getIdentifier();
+ ObjCIvarDecl *PrevIvar = CanonIntf->lookupInstanceVariable(II);
+ if (PrevIvar && PrevIvar != IVD) {
+ auto *ParentExt = dyn_cast<ObjCCategoryDecl>(IVD->getDeclContext());
+ auto *PrevParentExt =
+ dyn_cast<ObjCCategoryDecl>(PrevIvar->getDeclContext());
+ if (ParentExt && PrevParentExt) {
+ // Postpone diagnostic as we should merge identical extensions from
+ // different modules.
+ Reader
+ .PendingObjCExtensionIvarRedeclarations[std::make_pair(ParentExt,
+ PrevParentExt)]
+ .push_back(std::make_pair(IVD, PrevIvar));
+ } else {
+ Reader.Diag(IVD->getLocation(), diag::err_duplicate_ivar_declaration)
+ << II;
+ Reader.Diag(PrevIvar->getLocation(), diag::note_previous_definition);
+ }
+ }
}
void ASTDeclReader::ReadObjCDefinitionData(
Index: clang/lib/Serialization/ASTReader.cpp
===================================================================
--- clang/lib/Serialization/ASTReader.cpp
+++ clang/lib/Serialization/ASTReader.cpp
@@ -15,6 +15,7 @@
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/ASTStructuralEquivalence.h"
#include "clang/AST/ASTUnresolvedSet.h"
#include "clang/AST/AbstractTypeReader.h"
#include "clang/AST/Decl.h"
@@ -42,6 +43,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticError.h"
#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/ExceptionSpecificationType.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/FileSystemOptions.h"
@@ -9193,7 +9195,8 @@
while (!PendingIdentifierInfos.empty() || !PendingFunctionTypes.empty() ||
!PendingIncompleteDeclChains.empty() || !PendingDeclChains.empty() ||
!PendingMacroIDs.empty() || !PendingDeclContextInfos.empty() ||
- !PendingUpdateRecords.empty()) {
+ !PendingUpdateRecords.empty() ||
+ !PendingObjCExtensionIvarRedeclarations.empty()) {
// If any identifiers with corresponding top-level declarations have
// been loaded, load those declarations now.
using TopLevelDeclsMap =
@@ -9284,6 +9287,43 @@
ReadingKindTracker ReadingKind(Read_Decl, *this);
loadDeclUpdateRecords(Update);
}
+
+ while (!PendingObjCExtensionIvarRedeclarations.empty()) {
+ auto ExtensionsPair = PendingObjCExtensionIvarRedeclarations.back().first;
+ auto DuplicateIvars =
+ PendingObjCExtensionIvarRedeclarations.back().second;
+ llvm::DenseSet<std::pair<Decl *, Decl *>> NonEquivalentDecls;
+ StructuralEquivalenceContext Ctx(
+ ExtensionsPair.first->getASTContext(),
+ ExtensionsPair.second->getASTContext(), NonEquivalentDecls,
+ StructuralEquivalenceKind::Default, /*StrictTypeSpelling =*/false,
+ /*Complain =*/false,
+ /*ErrorOnTagTypeMismatch =*/true);
+ if (Ctx.IsEquivalent(ExtensionsPair.first, ExtensionsPair.second)) {
+ // Merge redeclared ivars with their predecessors.
+ for (auto IvarPair : DuplicateIvars) {
+ ObjCIvarDecl *Ivar = IvarPair.first, *PrevIvar = IvarPair.second;
+ // Change semantic DeclContext but keep the lexical one.
+ Ivar->setDeclContextsImpl(PrevIvar->getDeclContext(),
+ Ivar->getLexicalDeclContext(),
+ getContext());
+ getContext().setPrimaryMergedDecl(Ivar, PrevIvar->getCanonicalDecl());
+ }
+ // Invalidate duplicate extension and the cached ivar list.
+ ExtensionsPair.first->setInvalidDecl();
+ ExtensionsPair.second->getClassInterface()
+ ->getDefinition()
+ ->setIvarList(nullptr);
+ } else {
+ for (auto IvarPair : DuplicateIvars) {
+ Diag(IvarPair.first->getLocation(),
+ diag::err_duplicate_ivar_declaration)
+ << IvarPair.first->getIdentifier();
+ Diag(IvarPair.second->getLocation(), diag::note_previous_definition);
+ }
+ }
+ PendingObjCExtensionIvarRedeclarations.pop_back();
+ }
}
// At this point, all update records for loaded decls are in place, so any
Index: clang/lib/AST/DeclObjC.cpp
===================================================================
--- clang/lib/AST/DeclObjC.cpp
+++ clang/lib/AST/DeclObjC.cpp
@@ -1647,6 +1647,11 @@
ObjCIvarDecl *curIvar = nullptr;
if (!data().IvarList) {
+ // Force ivar deserialization upfront, before building IvarList.
+ (void)ivar_empty();
+ for (const auto *Ext : known_extensions()) {
+ (void)Ext->ivar_empty();
+ }
if (!ivar_empty()) {
ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end();
data().IvarList = *I; ++I;
@@ -1838,8 +1843,8 @@
ObjCIvarDecl::None, nullptr, false);
}
-const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const {
- const auto *DC = cast<ObjCContainerDecl>(getDeclContext());
+ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() {
+ auto *DC = cast<ObjCContainerDecl>(getDeclContext());
switch (DC->getKind()) {
default:
@@ -1849,7 +1854,7 @@
// Ivars can only appear in class extension categories.
case ObjCCategory: {
- const auto *CD = cast<ObjCCategoryDecl>(DC);
+ auto *CD = cast<ObjCCategoryDecl>(DC);
assert(CD->IsClassExtension() && "invalid container for ivar!");
return CD->getClassInterface();
}
Index: clang/include/clang/Serialization/ASTReader.h
===================================================================
--- clang/include/clang/Serialization/ASTReader.h
+++ clang/include/clang/Serialization/ASTReader.h
@@ -1106,6 +1106,18 @@
/// been completed.
std::deque<PendingDeclContextInfo> PendingDeclContextInfos;
+ template <typename DeclTy>
+ using DuplicateObjCDecls = std::pair<DeclTy *, DeclTy *>;
+
+ /// When resolving duplicate ivars from Objective-C extensions we don't error
+ /// out immediately but check if can merge identical extensions. Not checking
+ /// extensions for equality immediately because ivar deserialization isn't
+ /// over yet at that point.
+ llvm::SmallMapVector<DuplicateObjCDecls<ObjCCategoryDecl>,
+ llvm::SmallVector<DuplicateObjCDecls<ObjCIvarDecl>, 4>,
+ 2>
+ PendingObjCExtensionIvarRedeclarations;
+
/// The set of NamedDecls that have been loaded, but are members of a
/// context that has been merged into another context where the corresponding
/// declaration is either missing or has not yet been loaded.
Index: clang/include/clang/AST/DeclObjC.h
===================================================================
--- clang/include/clang/AST/DeclObjC.h
+++ clang/include/clang/AST/DeclObjC.h
@@ -1951,7 +1951,10 @@
/// in; this is either the interface where the ivar was declared, or the
/// interface the ivar is conceptually a part of in the case of synthesized
/// ivars.
- const ObjCInterfaceDecl *getContainingInterface() const;
+ ObjCInterfaceDecl *getContainingInterface();
+ const ObjCInterfaceDecl *getContainingInterface() const {
+ return const_cast<ObjCIvarDecl *>(this)->getContainingInterface();
+ }
ObjCIvarDecl *getNextIvar() { return NextIvar; }
const ObjCIvarDecl *getNextIvar() const { return NextIvar; }
@@ -2885,15 +2888,16 @@
}
inline bool ObjCInterfaceDecl::isVisibleCategory(ObjCCategoryDecl *Cat) {
- return Cat->isUnconditionallyVisible();
+ return !Cat->isInvalidDecl() && Cat->isUnconditionallyVisible();
}
inline bool ObjCInterfaceDecl::isVisibleExtension(ObjCCategoryDecl *Cat) {
- return Cat->IsClassExtension() && Cat->isUnconditionallyVisible();
+ return !Cat->isInvalidDecl() && Cat->IsClassExtension() &&
+ Cat->isUnconditionallyVisible();
}
inline bool ObjCInterfaceDecl::isKnownExtension(ObjCCategoryDecl *Cat) {
- return Cat->IsClassExtension();
+ return !Cat->isInvalidDecl() && Cat->IsClassExtension();
}
} // namespace clang
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits