Allow front-end 'isa' access on object's of type 'id'.
Enhance test case to cover 'isa' access on interface types (clang produces an error, GCC produces a warning). Still need back-end CodeGen for ObjCIsaExpr. llvm-svn: 76979
This commit is contained in:
parent
e2c6baf629
commit
e87026a08f
|
@ -496,6 +496,51 @@ public:
|
||||||
virtual child_iterator child_end();
|
virtual child_iterator child_end();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// ObjCIsaExpr - Represent X->isa and X.isa (similiar in spirit to MemberExpr).
|
||||||
|
class ObjCIsaExpr : public Expr {
|
||||||
|
/// Base - the expression for the base object pointer.
|
||||||
|
Stmt *Base;
|
||||||
|
|
||||||
|
/// IsaMemberLoc - This is the location of the 'isa'.
|
||||||
|
SourceLocation IsaMemberLoc;
|
||||||
|
|
||||||
|
/// IsArrow - True if this is "X->F", false if this is "X.F".
|
||||||
|
bool IsArrow;
|
||||||
|
public:
|
||||||
|
ObjCIsaExpr(Expr *base, bool isarrow, SourceLocation l, QualType ty)
|
||||||
|
: Expr(ObjCIsaExprClass, ty),
|
||||||
|
Base(base), IsaMemberLoc(l), IsArrow(isarrow) {}
|
||||||
|
|
||||||
|
/// \brief Build an empty expression.
|
||||||
|
explicit ObjCIsaExpr(EmptyShell Empty) : Expr(ObjCIsaExprClass, Empty) { }
|
||||||
|
|
||||||
|
void setBase(Expr *E) { Base = E; }
|
||||||
|
Expr *getBase() const { return cast<Expr>(Base); }
|
||||||
|
|
||||||
|
bool isArrow() const { return IsArrow; }
|
||||||
|
void setArrow(bool A) { IsArrow = A; }
|
||||||
|
|
||||||
|
/// getMemberLoc - Return the location of the "member", in X->F, it is the
|
||||||
|
/// location of 'F'.
|
||||||
|
SourceLocation getIsaMemberLoc() const { return IsaMemberLoc; }
|
||||||
|
void setIsaMemberLoc(SourceLocation L) { IsaMemberLoc = L; }
|
||||||
|
|
||||||
|
virtual SourceRange getSourceRange() const {
|
||||||
|
return SourceRange(getBase()->getLocStart(), IsaMemberLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SourceLocation getExprLoc() const { return IsaMemberLoc; }
|
||||||
|
|
||||||
|
static bool classof(const Stmt *T) {
|
||||||
|
return T->getStmtClass() == ObjCIsaExprClass;
|
||||||
|
}
|
||||||
|
static bool classof(const ObjCIsaExpr *) { return true; }
|
||||||
|
|
||||||
|
// Iterators
|
||||||
|
virtual child_iterator child_begin();
|
||||||
|
virtual child_iterator child_end();
|
||||||
|
};
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -141,6 +141,7 @@ EXPR(ObjCIvarRefExpr , Expr)
|
||||||
EXPR(ObjCPropertyRefExpr , Expr)
|
EXPR(ObjCPropertyRefExpr , Expr)
|
||||||
EXPR(ObjCKVCRefExpr , Expr)
|
EXPR(ObjCKVCRefExpr , Expr)
|
||||||
EXPR(ObjCSuperExpr , Expr)
|
EXPR(ObjCSuperExpr , Expr)
|
||||||
|
EXPR(ObjCIsaExpr , Expr)
|
||||||
|
|
||||||
// Clang Extensions.
|
// Clang Extensions.
|
||||||
EXPR(ShuffleVectorExpr , Expr)
|
EXPR(ShuffleVectorExpr , Expr)
|
||||||
|
|
|
@ -2189,7 +2189,6 @@ inline bool Type::isObjCClassType() const {
|
||||||
inline bool Type::isObjCBuiltinType() const {
|
inline bool Type::isObjCBuiltinType() const {
|
||||||
return isObjCIdType() || isObjCClassType();
|
return isObjCIdType() || isObjCClassType();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool Type::isTemplateTypeParmType() const {
|
inline bool Type::isTemplateTypeParmType() const {
|
||||||
return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
|
return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
|
||||||
}
|
}
|
||||||
|
|
|
@ -638,7 +638,9 @@ namespace clang {
|
||||||
EXPR_OBJC_MESSAGE_EXPR,
|
EXPR_OBJC_MESSAGE_EXPR,
|
||||||
/// \brief An ObjCSuperExpr record.
|
/// \brief An ObjCSuperExpr record.
|
||||||
EXPR_OBJC_SUPER_EXPR,
|
EXPR_OBJC_SUPER_EXPR,
|
||||||
|
/// \brief An ObjCIsa Expr record.
|
||||||
|
EXPR_OBJC_ISA,
|
||||||
|
|
||||||
/// \brief An ObjCForCollectionStmt record.
|
/// \brief An ObjCForCollectionStmt record.
|
||||||
STMT_OBJC_FOR_COLLECTION,
|
STMT_OBJC_FOR_COLLECTION,
|
||||||
/// \brief An ObjCAtCatchStmt record.
|
/// \brief An ObjCAtCatchStmt record.
|
||||||
|
|
|
@ -1878,6 +1878,10 @@ Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; }
|
||||||
Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); }
|
Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); }
|
||||||
Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); }
|
Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); }
|
||||||
|
|
||||||
|
// ObjCIsaExpr
|
||||||
|
Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; }
|
||||||
|
Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; }
|
||||||
|
|
||||||
// PredefinedExpr
|
// PredefinedExpr
|
||||||
Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); }
|
Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); }
|
||||||
Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); }
|
Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); }
|
||||||
|
|
|
@ -739,6 +739,11 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
|
||||||
// representing anonymous unions/structs
|
// representing anonymous unions/structs
|
||||||
OS << Node->getMemberDecl()->getNameAsString();
|
OS << Node->getMemberDecl()->getNameAsString();
|
||||||
}
|
}
|
||||||
|
void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
|
||||||
|
PrintExpr(Node->getBase());
|
||||||
|
OS << (Node->isArrow() ? "->isa" : ".isa");
|
||||||
|
}
|
||||||
|
|
||||||
void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
|
void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
|
||||||
PrintExpr(Node->getBase());
|
PrintExpr(Node->getBase());
|
||||||
OS << ".";
|
OS << ".";
|
||||||
|
|
|
@ -104,6 +104,7 @@ namespace {
|
||||||
unsigned VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
|
unsigned VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
|
||||||
unsigned VisitObjCMessageExpr(ObjCMessageExpr *E);
|
unsigned VisitObjCMessageExpr(ObjCMessageExpr *E);
|
||||||
unsigned VisitObjCSuperExpr(ObjCSuperExpr *E);
|
unsigned VisitObjCSuperExpr(ObjCSuperExpr *E);
|
||||||
|
unsigned VisitObjCIsaExpr(ObjCIsaExpr *E);
|
||||||
|
|
||||||
unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
|
unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
|
||||||
unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
|
unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
|
||||||
|
@ -448,6 +449,14 @@ unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned PCHStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) {
|
||||||
|
VisitExpr(E);
|
||||||
|
E->setBase(cast<Expr>(StmtStack.back()));
|
||||||
|
E->setIsaMemberLoc(SourceLocation::getFromRawEncoding(Record[Idx++]));
|
||||||
|
E->setArrow(Record[Idx++]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) {
|
unsigned PCHStmtReader::VisitCastExpr(CastExpr *E) {
|
||||||
VisitExpr(E);
|
VisitExpr(E);
|
||||||
E->setSubExpr(cast<Expr>(StmtStack.back()));
|
E->setSubExpr(cast<Expr>(StmtStack.back()));
|
||||||
|
@ -1106,6 +1115,9 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
|
||||||
case pch::EXPR_OBJC_SUPER_EXPR:
|
case pch::EXPR_OBJC_SUPER_EXPR:
|
||||||
S = new (Context) ObjCSuperExpr(Empty);
|
S = new (Context) ObjCSuperExpr(Empty);
|
||||||
break;
|
break;
|
||||||
|
case pch::EXPR_OBJC_ISA:
|
||||||
|
S = new (Context) ObjCIsaExpr(Empty);
|
||||||
|
break;
|
||||||
case pch::STMT_OBJC_FOR_COLLECTION:
|
case pch::STMT_OBJC_FOR_COLLECTION:
|
||||||
S = new (Context) ObjCForCollectionStmt(Empty);
|
S = new (Context) ObjCForCollectionStmt(Empty);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -97,6 +97,7 @@ namespace {
|
||||||
void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
|
void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
|
||||||
void VisitObjCMessageExpr(ObjCMessageExpr *E);
|
void VisitObjCMessageExpr(ObjCMessageExpr *E);
|
||||||
void VisitObjCSuperExpr(ObjCSuperExpr *E);
|
void VisitObjCSuperExpr(ObjCSuperExpr *E);
|
||||||
|
void VisitObjCIsaExpr(ObjCIsaExpr *E);
|
||||||
|
|
||||||
// Objective-C Statements
|
// Objective-C Statements
|
||||||
void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
|
void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
|
||||||
|
@ -416,6 +417,14 @@ void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
|
||||||
Code = pch::EXPR_MEMBER;
|
Code = pch::EXPR_MEMBER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PCHStmtWriter::VisitObjCIsaExpr(ObjCIsaExpr *E) {
|
||||||
|
VisitExpr(E);
|
||||||
|
Writer.WriteSubStmt(E->getBase());
|
||||||
|
Writer.AddSourceLocation(E->getIsaMemberLoc(), Record);
|
||||||
|
Record.push_back(E->isArrow());
|
||||||
|
Code = pch::EXPR_OBJC_ISA;
|
||||||
|
}
|
||||||
|
|
||||||
void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
|
void PCHStmtWriter::VisitCastExpr(CastExpr *E) {
|
||||||
VisitExpr(E);
|
VisitExpr(E);
|
||||||
Writer.WriteSubStmt(E->getSubExpr());
|
Writer.WriteSubStmt(E->getSubExpr());
|
||||||
|
|
|
@ -2283,7 +2283,6 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
const ObjCObjectPointerType *OPT = BaseType->getAsObjCObjectPointerType();
|
const ObjCObjectPointerType *OPT = BaseType->getAsObjCObjectPointerType();
|
||||||
const ObjCInterfaceType *IFaceT =
|
const ObjCInterfaceType *IFaceT =
|
||||||
OPT ? OPT->getInterfaceType() : BaseType->getAsObjCInterfaceType();
|
OPT ? OPT->getInterfaceType() : BaseType->getAsObjCInterfaceType();
|
||||||
|
|
||||||
if (IFaceT) {
|
if (IFaceT) {
|
||||||
ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
|
ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
|
||||||
ObjCInterfaceDecl *ClassDeclared;
|
ObjCInterfaceDecl *ClassDeclared;
|
||||||
|
@ -2340,7 +2339,11 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
<< IDecl->getDeclName() << &Member
|
<< IDecl->getDeclName() << &Member
|
||||||
<< BaseExpr->getSourceRange());
|
<< BaseExpr->getSourceRange());
|
||||||
}
|
}
|
||||||
// We don't have an interface. FIXME: deal with ObjC builtin 'id' type.
|
// We have an 'id' type. Rather than fall through, we check if this
|
||||||
|
// is a reference to 'isa'.
|
||||||
|
if (&Member == &Context.Idents.get("isa"))
|
||||||
|
return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc,
|
||||||
|
Context.getObjCIdType()));
|
||||||
}
|
}
|
||||||
// Handle properties on 'id' and qualified "id".
|
// Handle properties on 'id' and qualified "id".
|
||||||
if (OpKind == tok::period && (BaseType->isObjCIdType() ||
|
if (OpKind == tok::period && (BaseType->isObjCIdType() ||
|
||||||
|
@ -2472,6 +2475,13 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
|
||||||
<< &Member << BaseType);
|
<< &Member << BaseType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle the following exceptional case (*Obj).isa.
|
||||||
|
if (OpKind == tok::period &&
|
||||||
|
BaseType->isSpecificBuiltinType(BuiltinType::ObjCId) &&
|
||||||
|
&Member == &Context.Idents.get("isa"))
|
||||||
|
return Owned(new (Context) ObjCIsaExpr(BaseExpr, false, MemberLoc,
|
||||||
|
Context.getObjCIdType()));
|
||||||
|
|
||||||
// Handle 'field access' to vectors, such as 'V.xx'.
|
// Handle 'field access' to vectors, such as 'V.xx'.
|
||||||
if (BaseType->isExtVectorType()) {
|
if (BaseType->isExtVectorType()) {
|
||||||
QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
|
QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
|
||||||
|
|
|
@ -1340,6 +1340,12 @@ TemplateExprInstantiator::VisitObjCSuperExpr(ObjCSuperExpr *E) {
|
||||||
return SemaRef.ExprError();
|
return SemaRef.ExprError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Sema::OwningExprResult
|
||||||
|
TemplateExprInstantiator::VisitObjCIsaExpr(ObjCIsaExpr *E) {
|
||||||
|
assert(false && "FIXME: Template instantiations for ObjC expressions");
|
||||||
|
return SemaRef.ExprError();
|
||||||
|
}
|
||||||
|
|
||||||
Sema::OwningExprResult
|
Sema::OwningExprResult
|
||||||
Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
|
Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
|
||||||
if (!E)
|
if (!E)
|
||||||
|
|
|
@ -4,7 +4,11 @@ typedef struct objc_object {
|
||||||
struct objc_class *isa;
|
struct objc_class *isa;
|
||||||
} *id;
|
} *id;
|
||||||
|
|
||||||
@interface Whatever
|
@interface NSObject {
|
||||||
|
struct objc_class *isa;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
@interface Whatever : NSObject
|
||||||
+self;
|
+self;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@ -12,6 +16,19 @@ static void func() {
|
||||||
|
|
||||||
id x;
|
id x;
|
||||||
|
|
||||||
// FIXME: The following needs to compile without error. I will fix this tomorrow (7/15/09). Until I do, we will produce an error.
|
[(*x).isa self];
|
||||||
[x->isa self]; // expected-error {{member reference base type 'id' is not a structure or union}}
|
[x->isa self];
|
||||||
|
|
||||||
|
Whatever *y;
|
||||||
|
|
||||||
|
// GCC allows this, with the following warning:
|
||||||
|
// instance variable ‘isa’ is @protected; this will be a hard error in the future
|
||||||
|
//
|
||||||
|
// FIXME: see if we can avoid the 2 warnings that follow the error.
|
||||||
|
[(*y).isa self]; // expected-error {{instance variable 'isa' is protected}} \
|
||||||
|
expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
|
||||||
|
expected-warning{{method '-self' not found (return type defaults to 'id')}}
|
||||||
|
[y->isa self]; // expected-error {{instance variable 'isa' is protected}} \
|
||||||
|
expected-warning{{receiver type 'struct objc_class *' is not 'id' or interface pointer, consider casting it to 'id'}} \
|
||||||
|
expected-warning{{method '-self' not found (return type defaults to 'id')}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue