diff options
-rw-r--r-- | include/clang/AST/ExprObjC.h | 12 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 89 | ||||
-rw-r--r-- | test/SemaObjCXX/instantiate-expr.mm | 46 |
3 files changed, 136 insertions, 11 deletions
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 04b2c20b85..c62e91e31b 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -181,11 +181,12 @@ class ObjCIvarRefExpr : public Expr { public: ObjCIvarRefExpr(ObjCIvarDecl *d, - QualType t, SourceLocation l, Expr *base=0, + QualType t, SourceLocation l, Expr *base, bool arrow = false, bool freeIvar = false) : - Expr(ObjCIvarRefExprClass, t, false, false), D(d), - Loc(l), Base(base), IsArrow(arrow), - IsFreeIvar(freeIvar) {} + Expr(ObjCIvarRefExprClass, t, /*TypeDependent=*/false, + base->isValueDependent()), D(d), + Loc(l), Base(base), IsArrow(arrow), + IsFreeIvar(freeIvar) {} explicit ObjCIvarRefExpr(EmptyShell Empty) : Expr(ObjCIvarRefExprClass, Empty) {} @@ -773,7 +774,8 @@ class ObjCIsaExpr : public Expr { bool IsArrow; public: ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty) - : Expr(ObjCIsaExprClass, ty, false, false), + : Expr(ObjCIsaExprClass, ty, /*TypeDependent=*/false, + base->isValueDependent()), Base(base), IsaMemberLoc(l), IsArrow(isarrow) {} /// \brief Build an empty expression. diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f9bc0c7737..695ff6e524 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -1801,6 +1801,62 @@ public: move(Args)); } + /// \brief Build a new Objective-C ivar reference expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCIvarRefExpr(ExprArg BaseArg, ObjCIvarDecl *Ivar, + SourceLocation IvarLoc, + bool IsArrow, bool IsFreeIvar) { + // FIXME: We lose track of the IsFreeIvar bit. + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), Ivar->getDeclName(), IvarLoc, + Sema::LookupMemberName); + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/IvarLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/IvarLoc, IsArrow, SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + + /// \brief Build a new Objective-C "isa" expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + OwningExprResult RebuildObjCIsaExpr(ExprArg BaseArg, SourceLocation IsaLoc, + bool IsArrow) { + CXXScopeSpec SS; + Expr *Base = BaseArg.takeAs<Expr>(); + LookupResult R(getSema(), &getSema().Context.Idents.get("isa"), IsaLoc, + Sema::LookupMemberName); + OwningExprResult Result = getSema().LookupMemberExpr(R, Base, IsArrow, + /*FIME:*/IsaLoc, + SS, DeclPtrTy()); + if (Result.isInvalid()) + return getSema().ExprError(); + + if (Result.get()) + return move(Result); + + return getSema().BuildMemberReferenceExpr(getSema().Owned(Base), + Base->getType(), + /*FIXME:*/IsaLoc, IsArrow, SS, + /*FirstQualifierInScope=*/0, + R, + /*TemplateArgs=*/0); + } + /// \brief Build a new shuffle vector expression. /// /// By default, performs semantic analysis to build the new expression. @@ -5790,9 +5846,21 @@ TreeTransform<Derived>::TransformObjCProtocolExpr(ObjCProtocolExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - 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 ivar; it 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().RebuildObjCIvarRefExpr(move(Base), E->getDecl(), + E->getLocation(), + E->isArrow(), E->isFreeIvar()); } template<typename Derived> @@ -5822,9 +5890,18 @@ TreeTransform<Derived>::TransformObjCSuperExpr(ObjCSuperExpr *E) { template<typename Derived> Sema::OwningExprResult TreeTransform<Derived>::TransformObjCIsaExpr(ObjCIsaExpr *E) { - // FIXME: Implement this! - assert(false && "Cannot transform Objective-C expressions yet"); - return SemaRef.Owned(E->Retain()); + // Transform the base expression. + OwningExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return SemaRef.ExprError(); + + // If nothing changed, just retain the existing expression. + if (!getDerived().AlwaysRebuild() && + Base.get() == E->getBase()) + return SemaRef.Owned(E->Retain()); + + return getDerived().RebuildObjCIsaExpr(move(Base), E->getIsaMemberLoc(), + E->isArrow()); } template<typename Derived> diff --git a/test/SemaObjCXX/instantiate-expr.mm b/test/SemaObjCXX/instantiate-expr.mm new file mode 100644 index 0000000000..264ea634e8 --- /dev/null +++ b/test/SemaObjCXX/instantiate-expr.mm @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +@interface A { +@public + int ivar; +} +@end + +typedef struct objc_object { + Class isa; +} *id; + +// Test instantiation of value-dependent ObjCIvarRefExpr and +// ObjCIsaRefExpr nodes. +A *get_an_A(unsigned); +id get_an_id(unsigned); + +template<unsigned N, typename T, typename U> +void f(U value) { + get_an_A(N)->ivar = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}} + T c = get_an_id(N)->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}} +} + +template void f<6, Class>(int); +template void f<7, Class>(int*); // expected-note{{in instantiation of}} +template void f<8, int>(int); // expected-note{{in instantiation of}} + +// Test instantiation of unresolved member reference expressions to an +// ivar reference. +template<typename T, typename U> +void f2(T ptr, U value) { + ptr->ivar = value; // expected-error{{assigning to 'int' from incompatible type 'int *'}} +} + +template void f2(A*, int); +template void f2(A*, int*); // expected-note{{instantiation of}} + +// Test instantiation of unresolved member referfence expressions to +// an isa. +template<typename T, typename U> +void f3(U ptr) { + T c = ptr->isa; // expected-error{{cannot initialize a variable of type 'int' with an lvalue of type 'Class'}} +} + +template void f3<Class>(id); +template void f3<int>(id); // expected-note{{instantiation of}} |