]> granicus.if.org Git - clang/commitdiff
Allow front-end 'isa' access on object's of type 'id'.
authorSteve Naroff <snaroff@apple.com>
Fri, 24 Jul 2009 17:54:45 +0000 (17:54 +0000)
committerSteve Naroff <snaroff@apple.com>
Fri, 24 Jul 2009 17:54:45 +0000 (17:54 +0000)
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.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76979 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ExprObjC.h
include/clang/AST/StmtNodes.def
include/clang/AST/Type.h
include/clang/Frontend/PCHBitCodes.h
lib/AST/Expr.cpp
lib/AST/StmtPrinter.cpp
lib/Frontend/PCHReaderStmt.cpp
lib/Frontend/PCHWriterStmt.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaTemplateInstantiateExpr.cpp
test/SemaObjC/id-isa-ref.m

index e00833b5820e5029dfa545dcc5071e97e9c3e0d5..d610b3c01e3beacfeab64369b89996ceeaf0bff7 100644 (file)
@@ -496,6 +496,51 @@ public:
   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
 
 #endif
index a95a6273118601465b3b83c9df926660b52c6085..914ea2798b49fdfd5930c347b8e25fb432ff2b8f 100644 (file)
@@ -141,6 +141,7 @@ EXPR(ObjCIvarRefExpr      , Expr)
 EXPR(ObjCPropertyRefExpr  , Expr)
 EXPR(ObjCKVCRefExpr       , Expr)
 EXPR(ObjCSuperExpr        , Expr)
+EXPR(ObjCIsaExpr          , Expr)
 
 // Clang Extensions.
 EXPR(ShuffleVectorExpr    , Expr)
index 28f1c9d9d0a69e5d455f7bac7ffb1c09d5eab63e..5ef3539e693a46781735328d7b3bd03c9283f1ea 100644 (file)
@@ -2189,7 +2189,6 @@ inline bool Type::isObjCClassType() const {
 inline bool Type::isObjCBuiltinType() const {
   return isObjCIdType() || isObjCClassType();
 }
-
 inline bool Type::isTemplateTypeParmType() const {
   return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
 }
index 85d0c56bbbd7a68ab14668d76a2aa32ac83cb5bf..926ba224f42095e66dfdf87ec9da955611025045 100644 (file)
@@ -638,7 +638,9 @@ namespace clang {
       EXPR_OBJC_MESSAGE_EXPR,
       /// \brief An ObjCSuperExpr record.
       EXPR_OBJC_SUPER_EXPR,
-
+      /// \brief An ObjCIsa Expr record.
+      EXPR_OBJC_ISA,
+      
       /// \brief An ObjCForCollectionStmt record.      
       STMT_OBJC_FOR_COLLECTION,
       /// \brief An ObjCAtCatchStmt record.      
index efc37f768cfa65154abe61723a2eded0eb3af28e..b7b0a041e3365baec2f55cf9e54c737beb7fcdcf 100644 (file)
@@ -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_end() { return child_iterator(); }
 
+// ObjCIsaExpr
+Stmt::child_iterator ObjCIsaExpr::child_begin() { return &Base; }
+Stmt::child_iterator ObjCIsaExpr::child_end() { return &Base+1; }
+
 // PredefinedExpr
 Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); }
 Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); }
index 26732d4d296c5ce8962319c285a50f9b151c10b7..a5b0df8e45caac7fe798fb530b39a425704b13bb 100644 (file)
@@ -739,6 +739,11 @@ void StmtPrinter::VisitMemberExpr(MemberExpr *Node) {
   // representing anonymous unions/structs
   OS << Node->getMemberDecl()->getNameAsString();
 }
+void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) {
+  PrintExpr(Node->getBase());
+  OS << (Node->isArrow() ? "->isa" : ".isa");
+}
+
 void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) {
   PrintExpr(Node->getBase());
   OS << ".";
index 5681b675a2d5dfad91e170a59865a226d80c6344..16c0e79f4e775b04374577818cf81d22bffad261 100644 (file)
@@ -104,6 +104,7 @@ namespace {
     unsigned VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
     unsigned VisitObjCMessageExpr(ObjCMessageExpr *E);
     unsigned VisitObjCSuperExpr(ObjCSuperExpr *E);
+    unsigned VisitObjCIsaExpr(ObjCIsaExpr *E);
     
     unsigned VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
     unsigned VisitObjCAtCatchStmt(ObjCAtCatchStmt *);
@@ -448,6 +449,14 @@ unsigned PCHStmtReader::VisitMemberExpr(MemberExpr *E) {
   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) {
   VisitExpr(E);
   E->setSubExpr(cast<Expr>(StmtStack.back()));
@@ -1106,6 +1115,9 @@ Stmt *PCHReader::ReadStmt(llvm::BitstreamCursor &Cursor) {
     case pch::EXPR_OBJC_SUPER_EXPR:
       S = new (Context) ObjCSuperExpr(Empty);
       break;
+    case pch::EXPR_OBJC_ISA:
+      S = new (Context) ObjCIsaExpr(Empty);
+      break;
     case pch::STMT_OBJC_FOR_COLLECTION:
       S = new (Context) ObjCForCollectionStmt(Empty);
       break;
index ae606b6b411d03de14abf2b8ee99758d1414c357..3e4c6f5fedf49fec538d2fda80bd197c2cf4ba86 100644 (file)
@@ -97,6 +97,7 @@ namespace {
     void VisitObjCKVCRefExpr(ObjCKVCRefExpr *E);
     void VisitObjCMessageExpr(ObjCMessageExpr *E);
     void VisitObjCSuperExpr(ObjCSuperExpr *E);
+    void VisitObjCIsaExpr(ObjCIsaExpr *E);
     
     // Objective-C Statements    
     void VisitObjCForCollectionStmt(ObjCForCollectionStmt *);
@@ -416,6 +417,14 @@ void PCHStmtWriter::VisitMemberExpr(MemberExpr *E) {
   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) {
   VisitExpr(E);
   Writer.WriteSubStmt(E->getSubExpr());
index bfde991555a282691fc1a5060ee3bf082ebcffd7..66e73f99e90ab69cf4221506b66ce787b0c7b7ff 100644 (file)
@@ -2283,7 +2283,6 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
     const ObjCObjectPointerType *OPT = BaseType->getAsObjCObjectPointerType();
     const ObjCInterfaceType *IFaceT = 
       OPT ? OPT->getInterfaceType() : BaseType->getAsObjCInterfaceType();
-    
     if (IFaceT) {
       ObjCInterfaceDecl *IDecl = IFaceT->getDecl();
       ObjCInterfaceDecl *ClassDeclared;
@@ -2340,7 +2339,11 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
                          << IDecl->getDeclName() << &Member
                          << 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".
   if (OpKind == tok::period && (BaseType->isObjCIdType() || 
@@ -2472,6 +2475,13 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
       << &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'.
   if (BaseType->isExtVectorType()) {
     QualType ret = CheckExtVectorComponent(BaseType, OpLoc, Member, MemberLoc);
index 5e664add5cbfb39f2b3fbf8dc8a5d4935cb5a077..dcf2ebcd2ee18f2fbd60736f6912e0c981a613df 100644 (file)
@@ -1340,6 +1340,12 @@ TemplateExprInstantiator::VisitObjCSuperExpr(ObjCSuperExpr *E) {
   return SemaRef.ExprError();
 }
 
+Sema::OwningExprResult 
+TemplateExprInstantiator::VisitObjCIsaExpr(ObjCIsaExpr *E) { 
+  assert(false && "FIXME: Template instantiations for ObjC expressions");
+  return SemaRef.ExprError();
+}
+
 Sema::OwningExprResult 
 Sema::InstantiateExpr(Expr *E, const TemplateArgumentList &TemplateArgs) {
   if (!E)
index 1480a52e4a5f183ff3849ef3ece327d14014f7fe..dbb6b2f53d86e9ab34fd159f3a469dd3a1fff30a 100644 (file)
@@ -4,7 +4,11 @@ typedef struct objc_object {
   struct objc_class *isa;
 } *id;
 
-@interface Whatever
+@interface NSObject {
+  struct objc_class *isa;
+}
+@end
+@interface Whatever : NSObject
 +self;
 @end
 
@@ -12,6 +16,19 @@ static void func() {
  
   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]; // expected-error {{member reference base type 'id' is not a structure or union}}
+  [(*x).isa self];
+  [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')}}
 }