diff options
-rw-r--r-- | include/clang/AST/DeclObjC.h | 11 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 38 | ||||
-rw-r--r-- | lib/Sema/SemaObjCProperty.cpp | 20 | ||||
-rw-r--r-- | test/SemaObjC/synth-provisional-ivars.m | 40 |
5 files changed, 108 insertions, 6 deletions
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h index 30f63d8959..dee7504216 100644 --- a/include/clang/AST/DeclObjC.h +++ b/include/clang/AST/DeclObjC.h @@ -650,15 +650,17 @@ public: private: ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation L, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW) + QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, + bool synthesized) : FieldDecl(ObjCIvar, DC, L, Id, T, TInfo, BW, /*Mutable=*/false), - DeclAccess(ac) {} + DeclAccess(ac), Synthesized(synthesized) {} public: static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW = NULL); + AccessControl ac, Expr *BW = NULL, + bool synthesized=false); /// \brief Return the class interface that this ivar is logically contained /// in; this is either the interface where the ivar was declared, or the @@ -674,6 +676,8 @@ public: return DeclAccess == None ? Protected : AccessControl(DeclAccess); } + bool getSynthesize() const { return Synthesized; } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const ObjCIvarDecl *D) { return true; } @@ -681,6 +685,7 @@ public: private: // NOTE: VC++ treats enums as signed, avoid using the AccessControl enum unsigned DeclAccess : 3; + unsigned Synthesized : 1; }; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index adb0e7d083..fce24dcf38 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -575,7 +575,8 @@ bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation L, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW) { + AccessControl ac, Expr *BW, + bool synthesized) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized @@ -592,7 +593,7 @@ ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, "Invalid ivar decl context!"); } - return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW); + return new (C) ObjCIvarDecl(DC, L, Id, T, TInfo, ac, BW, synthesized); } const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5f46a977b1..d798d9d0e5 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -1005,6 +1005,38 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, return true; } +static ObjCIvarDecl *SynthesizeProvisionalIvar(Sema &SemaRef, + ASTContext &Context, + IdentifierInfo *II, + SourceLocation NameLoc) { + ObjCMethodDecl *CurMeth = SemaRef.getCurMethodDecl(); + ObjCInterfaceDecl *IDecl = CurMeth->getClassInterface(); + if (!IDecl) + return 0; + ObjCImplementationDecl *ClassImpDecl = IDecl->getImplementation(); + assert(ClassImpDecl && "Method not inside @implementation"); + bool DynamicImplSeen = false; + ObjCPropertyDecl *property = SemaRef.LookupPropertyDecl(IDecl, II); + if (!property) + return 0; + if (ObjCPropertyImplDecl *PIDecl = ClassImpDecl->FindPropertyImplDecl(II)) + DynamicImplSeen = + (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); + if (!DynamicImplSeen) { + QualType PropType = Context.getCanonicalType(property->getType()); + ObjCIvarDecl *Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, + NameLoc, + II, PropType, /*Dinfo=*/0, + ObjCIvarDecl::Protected, + (Expr *)0, true); + ClassImpDecl->addDecl(Ivar); + IDecl->makeDeclVisibleInContext(Ivar, false); + property->setPropertyIvarDecl(Ivar); + return Ivar; + } + return 0; +} + Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, UnqualifiedId &Id, @@ -1070,6 +1102,12 @@ Sema::OwningExprResult Sema::ActOnIdExpression(Scope *S, Expr *Ex = E.takeAs<Expr>(); if (Ex) return Owned(Ex); + // Synthesize ivars lazily + if (getLangOptions().ObjCNonFragileABI2) { + if (SynthesizeProvisionalIvar(*this, Context, II, NameLoc)) + return ActOnIdExpression(S, SS, Id, HasTrailingLParen, + isAddressOfOperand); + } } } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index ff60599b85..e7358edec3 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -372,7 +372,7 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, Ivar = ObjCIvarDecl::Create(Context, ClassImpDecl, PropertyLoc, PropertyIvar, PropType, /*Dinfo=*/0, ObjCIvarDecl::Protected, - (Expr *)0); + (Expr *)0, true); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar, false); property->setPropertyIvarDecl(Ivar); @@ -517,6 +517,24 @@ Sema::DeclPtrTy Sema::ActOnPropertyImplDecl(Scope *S, return DeclPtrTy(); } IC->addPropertyImplementation(PIDecl); + if (getLangOptions().ObjCNonFragileABI2) { + // Diagnose if an ivar was lazily synthesdized due to a previous + // use and if 1) property is @dynamic or 2) property is synthesized + // but it requires a dirreferently named ivar. + ObjCInterfaceDecl *ClassDeclared; + ObjCIvarDecl *Ivar = 0; + if (!Synthesize) + Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared); + else { + if (PropertyIvar && PropertyIvar != PropertyId) + Ivar = IDecl->lookupInstanceVariable(PropertyId, ClassDeclared); + } + if (Ivar && Ivar->getSynthesize()) { + Diag(Ivar->getLocation(), diag::err_undeclared_var_use) + << PropertyId; + Ivar->setInvalidDecl(); + } + } } else { if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = diff --git a/test/SemaObjC/synth-provisional-ivars.m b/test/SemaObjC/synth-provisional-ivars.m new file mode 100644 index 0000000000..2a1a6b15fa --- /dev/null +++ b/test/SemaObjC/synth-provisional-ivars.m @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -fsyntax-only -fobjc-nonfragile-abi2 -verify %s + +int bar; + +@interface I +{ + int _bar; +} +@property int PROP; +@property int PROP1; +@property int PROP2; +@property int PROP3; +@property int PROP4; + +@property int bar; +@property int bar1; + +@end + +@implementation I +- (int) Meth { return PROP; } // expected-note {{'PROP' declared here}} + +@dynamic PROP1; +- (int) Meth1 { return PROP1; } // expected-error {{use of undeclared identifier 'PROP1'}} + +- (int) Meth2 { return PROP2; } // expected-error {{use of undeclared identifier 'PROP2'}} +@dynamic PROP2; + +- (int) Meth3 { return PROP3; } // expected-error {{use of undeclared identifier 'PROP3'}} +@synthesize PROP3=IVAR; + +- (int) Meth4 { return PROP4; } +@synthesize PROP4=PROP4; + +- (int) Meth5 { return bar; } // expected-error {{use of undeclared identifier 'bar'}} +@synthesize bar = _bar; + +- (int) Meth6 { return bar1; } + +@end |