]> granicus.if.org Git - clang/commitdiff
Initial patch to support definitions of id and Class from headers in Objective-C...
authorDavid Chisnall <csdavec@swan.ac.uk>
Mon, 17 Aug 2009 16:35:33 +0000 (16:35 +0000)
committerDavid Chisnall <csdavec@swan.ac.uk>
Mon, 17 Aug 2009 16:35:33 +0000 (16:35 +0000)
This currently breaks test/SemaObjC/id-isa-ref.m and issues some spurious warnings when you attempt to assign a struct objc_class* value to a Class variable.  The test case probably should fail as it's written, because without the definition of Class the compiler should not assume struct objc_class* is a valid receiver type, but it's left broken because it would be nice if we could get that passing too for the special case of isa.

Approved by snaroff.

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

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/CodeGen/CGObjCGNU.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaExpr.cpp

index 3717c185528dffa79beb0e3d46000a640a0ee98a..0c1ccfddb7b4994ebb7e85a88319174093247a83 100644 (file)
@@ -202,6 +202,11 @@ public:
   llvm::OwningPtr<ExternalASTSource> ExternalSource;
   clang::PrintingPolicy PrintingPolicy;
 
+  // Typedefs which may be provided defining the structure of Objective-C
+  // pseudo-builtins
+  QualType ObjCIdRedefinitionType;
+  QualType ObjCClassRedefinitionType;
+
   /// \brief Source ranges for all of the comments in the source file,
   /// sorted in order of appearance in the translation unit.
   std::vector<SourceRange> Comments;
index dad09babccc271b7d3e5f3a9c84896294986c426..f0ab845f7c1ae2b5eec1330d103cca1edc874003 100644 (file)
@@ -43,6 +43,8 @@ ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM,
   LoadedExternalComments(false), FreeMemory(FreeMem), Target(t), 
   Idents(idents), Selectors(sels),
   BuiltinInfo(builtins), ExternalSource(0), PrintingPolicy(LOpts) {  
+  ObjCIdRedefinitionType = QualType();
+  ObjCClassRedefinitionType = QualType();
   if (size_reserve > 0) Types.reserve(size_reserve);    
   TUDecl = TranslationUnitDecl::Create(*this);
   InitBuiltinTypes();
index fc11cc8477f14daa90b3fc2cef012c8e5ae1d7f5..a292b2e7b77c77349599d8c24e23b306ba6b64fd 100644 (file)
@@ -53,6 +53,7 @@ private:
   const llvm::PointerType *PtrToInt8Ty;
   const llvm::FunctionType *IMPTy;
   const llvm::PointerType *IdTy;
+  QualType ASTIdTy;
   const llvm::IntegerType *IntTy;
   const llvm::PointerType *PtrTy;
   const llvm::IntegerType *LongTy;
@@ -226,8 +227,8 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
   PtrTy = PtrToInt8Ty;
  
   // Object type
-  IdTy = cast<llvm::PointerType>(
-                 CGM.getTypes().ConvertType(CGM.getContext().getObjCIdType()));
+  ASTIdTy = CGM.getContext().getObjCIdType();
+  IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
  
   // IMP type
   std::vector<const llvm::Type*> IMPArgs;
@@ -257,8 +258,8 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel) {
   llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()];
   if (US == 0)
     US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy),
-                               llvm::GlobalValue::InternalLinkage,
-                               ".objc_untyped_selector_alias",
+                               llvm::GlobalValue::PrivateLinkage,
+                               ".objc_untyped_selector_alias"+Sel.getAsString(),
                                NULL, &TheModule);
   
   return Builder.CreateLoad(US);
@@ -282,7 +283,7 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl
   // If it isn't, cache it.
   llvm::GlobalAlias *Sel = new llvm::GlobalAlias(
           llvm::PointerType::getUnqual(SelectorTy),
-          llvm::GlobalValue::InternalLinkage, SelName,
+          llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName,
           NULL, &TheModule);
   TypedSelectors[Selector] = Sel;
 
@@ -348,8 +349,8 @@ CGObjCGNU::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF,
   CallArgList ActualArgs;
 
   ActualArgs.push_back(
-         std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), 
-         CGF.getContext().getObjCIdType()));
+      std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)),
+      ASTIdTy));
   ActualArgs.push_back(std::make_pair(RValue::get(cmd),
                                       CGF.getContext().getObjCSelType()));
   ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
@@ -436,6 +437,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
                                bool IsClassMessage,
                                const CallArgList &CallArgs,
                                const ObjCMethodDecl *Method) {
+  IdTy = cast<llvm::PointerType>(CGM.getTypes().ConvertType(ASTIdTy));
   llvm::Value *cmd;
   if (Method)
     cmd = GetSelector(CGF.Builder, Method);
@@ -444,8 +446,7 @@ CGObjCGNU::GenerateMessageSend(CodeGen::CodeGenFunction &CGF,
   CallArgList ActualArgs;
 
   ActualArgs.push_back(
-    std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), 
-    CGF.getContext().getObjCIdType()));
+    std::make_pair(RValue::get(CGF.Builder.CreateBitCast(Receiver, IdTy)), ASTIdTy));
   ActualArgs.push_back(std::make_pair(RValue::get(cmd),
                                       CGF.getContext().getObjCSelType()));
   ActualArgs.insert(ActualArgs.end(), CallArgs.begin(), CallArgs.end());
@@ -495,6 +496,8 @@ llvm::Constant *CGObjCGNU::GenerateMethodList(const std::string &ClassName,
     const llvm::SmallVectorImpl<Selector> &MethodSels, 
     const llvm::SmallVectorImpl<llvm::Constant *> &MethodTypes, 
     bool isClassMethodList) {
+  if (MethodSels.empty())
+    return NULLPtr;
   // Get the method structure type.  
   llvm::StructType *ObjCMethodTy = llvm::StructType::get(VMContext,
     PtrToInt8Ty, // Really a selector, but the runtime creates it us.
@@ -1257,7 +1260,7 @@ llvm::Constant *CGObjCGNU::EnumerationMutationFunction() {
   ASTContext &Ctx = CGM.getContext();
   // void objc_enumerationMutation (id)
   llvm::SmallVector<QualType,16> Params;
-  Params.push_back(Ctx.getObjCIdType());
+  Params.push_back(ASTIdTy);
   const llvm::FunctionType *FTy =
     Types.GetFunctionType(Types.getFunctionInfo(Ctx.VoidTy, Params), false);
   return CGM.CreateRuntimeFunction(FTy, "objc_enumerationMutation");
index 53a5f6d80f8a472f67be17778bbaa8c516a2aa17..5425c4fb5abcf35683b927f34c96f96f20a97796 100644 (file)
@@ -159,6 +159,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
       );
     PushOnScopeChains(IdTypedef, TUScope);
     Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
+    Context.ObjCIdRedefinitionType = Context.getObjCIdType();
   }
   // Create the built-in typedef for 'Class'.
   if (Context.getObjCClassType().isNull()) {
@@ -169,6 +170,7 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
       );
     PushOnScopeChains(ClassTypedef, TUScope);
     Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
+    Context.ObjCClassRedefinitionType = Context.getObjCClassType();
   }
 }
 
index 612c4dc4cbfa3fa1382f9d00fdf10db809eca2e0..5499e6cb4ed5b966c1b0e61a755ca8d97a416081 100644 (file)
@@ -1257,7 +1257,7 @@ Sema::CheckReturnStackAddr(Expr *RetValExp, QualType lhsType,
 ///   * taking the address of an array element where the array is on the stack
 static DeclRefExpr* EvalAddr(Expr *E) {
   // We should only be called for evaluating pointer expressions.
-  assert((E->getType()->isPointerType() ||
+  assert((E->getType()->isAnyPointerType() ||
           E->getType()->isBlockPointerType() ||
           E->getType()->isObjCQualifiedIdType()) &&
          "EvalAddr only works on pointers");
index b672d0501a0498dbc69f6bed6403a62e41cda40b..f6988d174df5f713972e14068526e978e89e628d 100644 (file)
@@ -534,12 +534,14 @@ void Sema::MergeTypeDefDecl(TypedefDecl *New, Decl *OldD) {
     case 2: 
       if (!TypeID->isStr("id"))
         break;
+      Context.ObjCIdRedefinitionType = New->getUnderlyingType();
       // Install the built-in type for 'id', ignoring the current definition.
       New->setTypeForDecl(Context.getObjCIdType().getTypePtr());
       return;
     case 5:
       if (!TypeID->isStr("Class"))
         break;
+      Context.ObjCClassRedefinitionType = New->getUnderlyingType();
       // Install the built-in type for 'Class', ignoring the current definition.
       New->setTypeForDecl(Context.getObjCClassType().getTypePtr());
       return;
index ef172e5937d7d88c53e68f2f01206a5ba2778717..6b597d117df47b75fc06efb3c5e63045de32c9ff 100644 (file)
@@ -26,6 +26,7 @@
 #include "clang/Parse/Scope.h"
 using namespace clang;
 
+
 /// \brief Determine whether the use of this declaration is valid, and
 /// emit any corresponding diagnostics.
 ///
@@ -2127,6 +2128,20 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
   DefaultFunctionArrayConversion(BaseExpr);
 
   QualType BaseType = BaseExpr->getType();
+  // If this is an Objective-C pseudo-builtin and a definition is provided then
+  // use that.
+  if (BaseType->isObjCIdType()) {
+    // We have an 'id' type. Rather than fall through, we check if this
+    // is a reference to 'isa'.
+    if (BaseType != Context.ObjCIdRedefinitionType) {
+      BaseType = Context.ObjCIdRedefinitionType;
+      ImpCastExprToType(BaseExpr, BaseType);
+    }
+  } else if (BaseType->isObjCClassType() &&
+      BaseType != Context.ObjCClassRedefinitionType) {
+    BaseType = Context.ObjCClassRedefinitionType;
+    ImpCastExprToType(BaseExpr, BaseType);
+  }
   assert(!BaseType.isNull() && "no type for member expression");
 
   // Get the type being accessed in BaseType.  If this is an arrow, the BaseExpr
@@ -2402,11 +2417,6 @@ Sema::ActOnMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
                          << IDecl->getDeclName() << &Member
                          << BaseExpr->getSourceRange());
     }
-    // We have an 'id' type. Rather than fall through, we check if this
-    // is a reference to 'isa'.
-    if (Member.isStr("isa"))
-      return Owned(new (Context) ObjCIsaExpr(BaseExpr, true, MemberLoc,
-                                             Context.getObjCIdType()));
   }
   // Handle properties on 'id' and qualified "id".
   if (OpKind == tok::period && (BaseType->isObjCIdType() || 
@@ -3266,6 +3276,30 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
     ImpCastExprToType(LHS, RHSTy); // promote the null to a pointer.
     return RHSTy;
   }
+  // Handle things like Class and struct objc_class*.  Here we case the result
+  // to the pseudo-builtin, because that will be implicitly cast back to the
+  // redefinition type if an attempt is made to access its fields.
+  if (LHSTy->isObjCClassType() &&
+      (RHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+    ImpCastExprToType(RHS, LHSTy);
+    return LHSTy;
+  }
+  if (RHSTy->isObjCClassType() &&
+      (LHSTy.getDesugaredType() == Context.ObjCClassRedefinitionType)) {
+    ImpCastExprToType(LHS, RHSTy);
+    return RHSTy;
+  }
+  // And the same for struct objc_object* / id
+  if (LHSTy->isObjCIdType() &&
+      (RHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+    ImpCastExprToType(RHS, LHSTy);
+    return LHSTy;
+  }
+  if (RHSTy->isObjCIdType() &&
+      (LHSTy.getDesugaredType() == Context.ObjCIdRedefinitionType)) {
+    ImpCastExprToType(LHS, RHSTy);
+    return RHSTy;
+  }
   // Handle block pointer types.
   if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
     if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
@@ -3484,6 +3518,13 @@ Sema::AssignConvertType
 Sema::CheckPointerTypesForAssignment(QualType lhsType, QualType rhsType) {
   QualType lhptee, rhptee;
 
+  if ((lhsType->isObjCClassType() &&
+       (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+     (rhsType->isObjCClassType() &&
+       (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+      return Compatible;
+  }
+
   // get the "pointed to" type (ignoring qualifiers at the top level)
   lhptee = lhsType->getAs<PointerType>()->getPointeeType();
   rhptee = rhsType->getAs<PointerType>()->getPointeeType();
@@ -3607,6 +3648,13 @@ Sema::CheckAssignmentConstraints(QualType lhsType, QualType rhsType) {
   if (lhsType == rhsType)
     return Compatible; // Common case: fast path an exact match.
 
+  if ((lhsType->isObjCClassType() &&
+       (rhsType.getDesugaredType() == Context.ObjCClassRedefinitionType)) ||
+     (rhsType->isObjCClassType() &&
+       (lhsType.getDesugaredType() == Context.ObjCClassRedefinitionType))) {
+      return Compatible;
+  }
+
   // If the left-hand side is a reference type, then we are in a
   // (rare!) case where we've allowed the use of references in C,
   // e.g., as a parameter type in a built-in function. In this case,