From: David Chisnall Date: Mon, 17 Aug 2009 16:35:33 +0000 (+0000) Subject: Initial patch to support definitions of id and Class from headers in Objective-C... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0f436560640a1cff5b6d96f80f540770f139453f;p=clang Initial patch to support definitions of id and Class from headers in Objective-C code. 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 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 3717c18552..0c1ccfddb7 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -202,6 +202,11 @@ public: llvm::OwningPtr 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 Comments; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index dad09babcc..f0ab845f7c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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(); diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index fc11cc8477..a292b2e7b7 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -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( - CGM.getTypes().ConvertType(CGM.getContext().getObjCIdType())); + ASTIdTy = CGM.getContext().getObjCIdType(); + IdTy = cast(CGM.getTypes().ConvertType(ASTIdTy)); // IMP type std::vector 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(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 &MethodSels, const llvm::SmallVectorImpl &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 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"); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 53a5f6d80f..5425c4fb5a 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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(); } } diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 612c4dc4cb..5499e6cb4e 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -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"); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index b672d0501a..f6988d174d 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index ef172e5937..6b597d117d 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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()->getPointeeType(); rhptee = rhsType->getAs()->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,