diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 406b905888..8a09f4e9a6 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -299,7 +299,8 @@ public: QualType t, ObjCMethodDecl *setter, SourceLocation l, Expr *base) - : Expr(ObjCImplicitSetterGetterRefExprClass, t, false, false), + : Expr(ObjCImplicitSetterGetterRefExprClass, t, /*TypeDependent=*/false, + base->isValueDependent()), Setter(setter), Getter(getter), MemberLoc(l), Base(base), InterfaceDecl(0), ClassLoc(SourceLocation()) { } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 946496ae12..cded16cd60 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1860,6 +1860,26 @@ public: /*TemplateArgs=*/0); } + /// \brief Build a new Objective-C implicit setter/getter reference + /// expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCImplicitSetterGetterRefExpr( + ObjCMethodDecl *Getter, + QualType T, + ObjCMethodDecl *Setter, + SourceLocation NameLoc, + ExprArg Base) { + // Since these expressions can only be value-dependent, we do not need to + // perform semantic analysis again. + return getSema().Owned( + new (getSema().Context) ObjCImplicitSetterGetterRefExpr(Getter, T, + Setter, + NameLoc, + Base.takeAs())); + } + /// \brief Build a new Objective-C "isa" expression. /// /// By default, performs semantic analysis to build the new expression. @@ -5916,9 +5936,30 @@ template Sema::OwningExprResult TreeTransform::TransformObjCImplicitSetterGetterRefExpr( ObjCImplicitSetterGetterRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // If this implicit setter/getter refers to class methods, it cannot have any + // dependent parts. Just retain the existing declaration. + if (E->getInterfaceDecl()) + return SemaRef.Owned(E->Retain()); + + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // We don't need to transform the getters/setters; they will never change. + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCImplicitSetterGetterRefExpr( + E->getGetterMethod(), + E->getType(), + E->getSetterMethod(), + E->getLocation(), + move(Base)); + } template diff --git a/test/SemaObjCXX/instantiate-expr.mm b/test/SemaObjCXX/instantiate-expr.mm index c480ecfa88..08be5f7b91 100644 --- a/test/SemaObjCXX/instantiate-expr.mm +++ b/test/SemaObjCXX/instantiate-expr.mm @@ -49,3 +49,25 @@ void f3(U ptr) { template void f3(id); template void f3(id); // expected-note{{instantiation of}} + +// Implicit setter/getter +@interface B +- (int)foo; +- (void)setFoo:(int)value; +@end + +template +void f4(B *b, T value) { + b.foo = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}} +} + +template void f4(B*, int); +template void f4(B*, int*); // expected-note{{in instantiation of function template specialization 'f4' requested here}} + +template +void f5(T ptr, U value) { + ptr.foo = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}} +} + +template void f5(B*, int); +template void f5(B*, int*); // expected-note{{in instantiation of function template specialization 'f5' requested here}}