diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td index eda735658ebe..7d45bc58463c 100644 --- a/clang/include/clang/Basic/DiagnosticASTKinds.td +++ b/clang/include/clang/Basic/DiagnosticASTKinds.td @@ -56,6 +56,8 @@ def note_odr_number_of_bases : Note< "class has %0 base %plural{1:class|:classes}0">; def note_odr_enumerator : Note<"enumerator %0 with value %1 here">; def note_odr_missing_enumerator : Note<"no corresponding enumerator here">; + +// Importing Objective-C ASTs def err_odr_ivar_type_inconsistent : Error< "instance variable %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; @@ -80,6 +82,18 @@ def note_odr_objc_method_here : Note< def err_odr_objc_property_type_inconsistent : Error< "property %0 declared with incompatible types in different " "translation units (%1 vs. %2)">; +def err_odr_objc_property_impl_kind_inconsistent : Error< + "property %0 is implemented with %select{@synthesize|@dynamic}1 in one " + "translation but %select{@dynamic|@synthesize}1 in another translation unit">; +def note_odr_objc_property_impl_kind : Note< + "property %0 is implemented with %select{@synthesize|@dynamic}1 here">; +def err_odr_objc_synthesize_ivar_inconsistent : Error< + "property %0 is synthesized to different ivars in different translation " + "units (%1 vs. %2)">; +def note_odr_objc_synthesize_ivar_here : Note< + "property is synthesized to ivar %0 here">; + +// Importing C++ ASTs def err_odr_different_num_template_parameters : Error< "template parameter lists have a different number of parameters (%0 vs %1)">; def note_odr_template_parameter_list : Note< diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index c5314059c088..7a6afbd560e1 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -118,6 +118,7 @@ namespace { Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D); Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D); + Decl *VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); Decl *VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); Decl *VisitObjCClassDecl(ObjCClassDecl *D); Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); @@ -3195,6 +3196,87 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { return ToProperty; } +Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *Property = cast_or_null( + Importer.Import(D->getPropertyDecl())); + if (!Property) + return 0; + + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + // Import the lexical declaration context. + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + ObjCImplDecl *InImpl = dyn_cast(LexicalDC); + if (!InImpl) + return 0; + + // Import the ivar (for an @synthesize). + ObjCIvarDecl *Ivar = 0; + if (D->getPropertyIvarDecl()) { + Ivar = cast_or_null( + Importer.Import(D->getPropertyIvarDecl())); + if (!Ivar) + return 0; + } + + ObjCPropertyImplDecl *ToImpl + = InImpl->FindPropertyImplDecl(Property->getIdentifier()); + if (!ToImpl) { + ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Importer.Import(D->getLocation()), + Property, + D->getPropertyImplementation(), + Ivar, + Importer.Import(D->getPropertyIvarDeclLoc())); + ToImpl->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToImpl); + LexicalDC->addDecl(ToImpl); + } else { + // Check that we have the same kind of property implementation (@synthesize + // vs. @dynamic). + if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) { + Importer.ToDiag(ToImpl->getLocation(), + diag::err_odr_objc_property_impl_kind_inconsistent) + << Property->getDeclName() + << (ToImpl->getPropertyImplementation() + == ObjCPropertyImplDecl::Dynamic); + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_property_impl_kind) + << D->getPropertyDecl()->getDeclName() + << (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); + return 0; + } + + // For @synthesize, check that we have the same + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize && + Ivar != ToImpl->getPropertyIvarDecl()) { + Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), + diag::err_odr_objc_synthesize_ivar_inconsistent) + << Property->getDeclName() + << ToImpl->getPropertyIvarDecl()->getDeclName() + << Ivar->getDeclName(); + Importer.FromDiag(D->getPropertyIvarDeclLoc(), + diag::note_odr_objc_synthesize_ivar_here) + << D->getPropertyIvarDecl()->getDeclName(); + return 0; + } + + // Merge the existing implementation with the new implementation. + Importer.Imported(D, ToImpl); + } + + return ToImpl; +} + Decl * ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { // Import the context of this declaration. diff --git a/clang/test/ASTMerge/Inputs/property1.m b/clang/test/ASTMerge/Inputs/property1.m index 37887a34f767..22fe0a02220c 100644 --- a/clang/test/ASTMerge/Inputs/property1.m +++ b/clang/test/ASTMerge/Inputs/property1.m @@ -10,3 +10,22 @@ @property (readonly) float Prop1; @end +// Properties with implementations +@interface I3 { + int ivar1; + int ivar2; + int ivar3; + int Prop4; +} +@property int Prop1; +@property int Prop2; +@property int Prop3; +@property int Prop4; +@end + +@implementation I3 +@synthesize Prop1 = ivar1; +@synthesize Prop2 = ivar3; +@dynamic Prop3; +@synthesize Prop4; +@end diff --git a/clang/test/ASTMerge/Inputs/property2.m b/clang/test/ASTMerge/Inputs/property2.m index 6039f10ec6e8..64a03fb04ec3 100644 --- a/clang/test/ASTMerge/Inputs/property2.m +++ b/clang/test/ASTMerge/Inputs/property2.m @@ -11,3 +11,23 @@ @interface I2 @property (readonly) int Prop1; @end + +// Properties with implementations +@interface I3 { + int ivar1; + int ivar2; + int ivar3; + int Prop4; +} +@property int Prop1; +@property int Prop2; +@property int Prop3; +@property int Prop4; +@end + +@implementation I3 +@synthesize Prop2 = ivar2; +@synthesize Prop1 = ivar1; +@synthesize Prop3 = ivar3; +@synthesize Prop4 = Prop4; +@end diff --git a/clang/test/ASTMerge/property.m b/clang/test/ASTMerge/property.m index 5f7a7308da65..a8dd7c420c89 100644 --- a/clang/test/ASTMerge/property.m +++ b/clang/test/ASTMerge/property.m @@ -6,4 +6,8 @@ // CHECK: property1.m:10:28: note: declared here with type 'float' // CHECK: property2.m:12:26: error: instance method 'Prop1' has incompatible result types in different translation units ('int' vs. 'float') // CHECK: property1.m:10:28: note: instance method 'Prop1' also declared here -// CHECK: 2 errors generated. +// CHECK: property1.m:28:21: error: property 'Prop2' is synthesized to different ivars in different translation units ('ivar3' vs. 'ivar2') +// CHECK: property2.m:29:21: note: property is synthesized to ivar 'ivar2' here +// CHECK: property1.m:29:10: error: property 'Prop3' is implemented with @dynamic in one translation but @synthesize in another translation unit +// CHECK: property2.m:31:13: note: property 'Prop3' is implemented with @synthesize here +// CHECK: 4 errors generated.