diff options
-rw-r--r-- | include/clang/AST/ExprObjC.h | 8 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 1 | ||||
-rw-r--r-- | lib/CodeGen/CGExprConstant.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 6 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCGNU.cpp | 61 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCMac.cpp | 8 | ||||
-rw-r--r-- | lib/CodeGen/CGObjCRuntime.h | 6 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 15 |
8 files changed, 84 insertions, 29 deletions
diff --git a/include/clang/AST/ExprObjC.h b/include/clang/AST/ExprObjC.h index 0b0cd64ad7..3a625273ad 100644 --- a/include/clang/AST/ExprObjC.h +++ b/include/clang/AST/ExprObjC.h @@ -96,18 +96,22 @@ public: /// ObjCSelectorExpr used for @selector in Objective-C. class ObjCSelectorExpr : public Expr { Selector SelName; + ObjCMethodDecl *Method; SourceLocation AtLoc, RParenLoc; public: ObjCSelectorExpr(QualType T, Selector selInfo, SourceLocation at, SourceLocation rp) - : Expr(ObjCSelectorExprClass, T, false, false), SelName(selInfo), AtLoc(at), - RParenLoc(rp){} + : Expr(ObjCSelectorExprClass, T, false, false), SelName(selInfo), Method(0), + AtLoc(at), RParenLoc(rp){} explicit ObjCSelectorExpr(EmptyShell Empty) : Expr(ObjCSelectorExprClass, Empty) {} Selector getSelector() const { return SelName; } void setSelector(Selector S) { SelName = S; } + ObjCMethodDecl *getMethodDecl() const { return Method; } + void setMethodDecl(ObjCMethodDecl *M) { Method = M; } + SourceLocation getAtLoc() const { return AtLoc; } SourceLocation getRParenLoc() const { return RParenLoc; } void setAtLoc(SourceLocation L) { AtLoc = L; } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 50ddc9156a..4811a6954a 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1454,6 +1454,7 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { case StringLiteralClass: case ObjCStringLiteralClass: case ObjCEncodeExprClass: + case ObjCSelectorExprClass: return true; case CompoundLiteralExprClass: { // This handles gcc's extension that allows global initializers like diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index 81209da6c6..ca775bf050 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -701,6 +701,14 @@ public: CGM.GetStringForStringLiteral(E), false); } + llvm::Constant *VisitObjCSelectorExpr(const ObjCSelectorExpr *E) { + ObjCMethodDecl *OMD = E->getMethodDecl(); + if (OMD) + return CGM.getObjCRuntime().GetConstantTypedSelector(OMD); + else + return CGM.getObjCRuntime().GetConstantSelector(E->getSelector()); + } + llvm::Constant *VisitObjCEncodeExpr(ObjCEncodeExpr *E) { // This must be an @encode initializing an array in a static initializer. // Don't emit it as the address of the string, emit the string data itself diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 896d2207ea..e4421670ff 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -38,7 +38,11 @@ llvm::Value *CodeGenFunction::EmitObjCSelectorExpr(const ObjCSelectorExpr *E) { // Note that this implementation allows for non-constant strings to be passed // as arguments to @selector(). Currently, the only thing preventing this // behaviour is the type checking in the front end. - return CGM.getObjCRuntime().GetSelector(Builder, E->getSelector()); + ObjCMethodDecl *OMD = E->getMethodDecl(); + if (OMD) + return CGM.getObjCRuntime().GetSelector(Builder, OMD); + else + return CGM.getObjCRuntime().GetSelector(Builder, E->getSelector()); } llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 3a0ac994d8..d69477852a 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -146,9 +146,17 @@ public: const ObjCMethodDecl *Method); virtual llvm::Value *GetClass(CGBuilderTy &Builder, const ObjCInterfaceDecl *OID); - virtual llvm::Value *GetSelector(CGBuilderTy &Builder, Selector Sel); - virtual llvm::Value *GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl - *Method); + virtual llvm::Constant *GetConstantSelector(Selector Sel); + virtual llvm::Constant *GetConstantTypedSelector( + const ObjCMethodDecl *Method); + llvm::Value *GetSelector(CGBuilderTy &Builder, + Selector Sel) { + return cast<llvm::Constant>((GetConstantSelector(Sel))); + } + llvm::Value *GetSelector(CGBuilderTy &Builder, + const ObjCMethodDecl *Method) { + return cast<llvm::Constant>(GetConstantTypedSelector(Method)); + } virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD); @@ -287,18 +295,18 @@ llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder, return Builder.CreateCall(ClassLookupFn, ClassName); } -llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, Selector Sel) { +llvm::Constant *CGObjCGNU::GetConstantSelector(Selector Sel) { llvm::GlobalAlias *&US = UntypedSelectors[Sel.getAsString()]; if (US == 0) - US = new llvm::GlobalAlias(llvm::PointerType::getUnqual(SelectorTy), + US = new llvm::GlobalAlias(SelectorTy, llvm::GlobalValue::PrivateLinkage, ".objc_untyped_selector_alias"+Sel.getAsString(), NULL, &TheModule); - return Builder.CreateLoad(US); + return US; } -llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl +llvm::Constant *CGObjCGNU::GetConstantTypedSelector(const ObjCMethodDecl *Method) { std::string SelName = Method->getSelector().getAsString(); @@ -310,17 +318,17 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl // If it's already cached, return it. if (TypedSelectors[Selector]) { - return Builder.CreateLoad(TypedSelectors[Selector]); + return TypedSelectors[Selector]; } // If it isn't, cache it. llvm::GlobalAlias *Sel = new llvm::GlobalAlias( - llvm::PointerType::getUnqual(SelectorTy), + SelectorTy, llvm::GlobalValue::PrivateLinkage, ".objc_selector_alias" + SelName, NULL, &TheModule); TypedSelectors[Selector] = Sel; - return Builder.CreateLoad(Sel); + return Sel; } llvm::Constant *CGObjCGNU::MakeConstantString(const std::string &Str, @@ -1461,40 +1469,43 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // Now that all of the static selectors exist, create pointers to them. int index = 0; + llvm::SmallVector<std::pair<llvm::GlobalAlias*,llvm::Value*>, 16> selectors; for (std::map<TypedSelector, llvm::GlobalAlias*>::iterator iter=TypedSelectors.begin(), iterEnd =TypedSelectors.end(); iter != iterEnd; ++iter) { llvm::Constant *Idxs[] = {Zeros[0], llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable(TheModule, SelStructPtrTy, - true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - ".objc_sel_ptr"); + llvm::Constant *SelPtr = + llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2); // If selectors are defined as an opaque type, cast the pointer to this // type. if (isSelOpaque) { - SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, - llvm::PointerType::getUnqual(SelectorTy)); + SelPtr = llvm::ConstantExpr::getBitCast(SelPtr,SelectorTy); } - (*iter).second->setAliasee(SelPtr); + selectors.push_back( + std::pair<llvm::GlobalAlias*,llvm::Value*>((*iter).second, SelPtr)); } for (llvm::StringMap<llvm::GlobalAlias*>::iterator iter=UntypedSelectors.begin(), iterEnd = UntypedSelectors.end(); iter != iterEnd; iter++) { llvm::Constant *Idxs[] = {Zeros[0], llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), index++), Zeros[0]}; - llvm::Constant *SelPtr = new llvm::GlobalVariable - (TheModule, SelStructPtrTy, - true, llvm::GlobalValue::InternalLinkage, - llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2), - ".objc_sel_ptr"); + llvm::Constant *SelPtr = + llvm::ConstantExpr::getGetElementPtr(SelectorList, Idxs, 2); // If selectors are defined as an opaque type, cast the pointer to this // type. if (isSelOpaque) { - SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, - llvm::PointerType::getUnqual(SelectorTy)); + SelPtr = llvm::ConstantExpr::getBitCast(SelPtr, SelectorTy); } - (*iter).second->setAliasee(SelPtr); + selectors.push_back( + std::pair<llvm::GlobalAlias*,llvm::Value*>((*iter).second, SelPtr)); + } + for (llvm::SmallVectorImpl<std::pair< + llvm::GlobalAlias*,llvm::Value*> >::iterator + iter=selectors.begin(), iterEnd =selectors.end(); + iter != iterEnd; ++iter) { + iter->first->replaceAllUsesWith(iter->second); + iter->first->eraseFromParent(); } // Number of classes defined. Elements.push_back(llvm::ConstantInt::get(llvm::Type::getInt16Ty(VMContext), diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 0dcbe829e2..361afbc58e 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -953,6 +953,14 @@ public: CGObjCCommonMac(CodeGen::CodeGenModule &cgm) : CGM(cgm), VMContext(cgm.getLLVMContext()) { } + virtual llvm::Constant *GetConstantSelector(Selector Sel) { + assert(0 && "Constant Selectors are not yet supported on the Mac runtimes"); + return 0; + } + virtual llvm::Constant *GetConstantTypedSelector( + const ObjCMethodDecl *Method) { + return GetConstantSelector(Method->getSelector()); + } virtual llvm::Constant *GenerateConstantString(const StringLiteral *SL); virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index ff5d40bfbc..2c27c14031 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -95,6 +95,12 @@ public: /// this compilation unit with the runtime library. virtual llvm::Function *ModuleInitFunction() = 0; + virtual llvm::Constant *GetConstantSelector(Selector Sel) = 0; + + /// Get a typed selector. + virtual llvm::Constant *GetConstantTypedSelector( + const ObjCMethodDecl *Method) = 0; + /// Get a selector for the specified name and type values. The /// return value should have the LLVM type for pointer-to /// ASTContext::getObjCSelType(). diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 85956c3e7e..8ce782b961 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -140,7 +140,20 @@ Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, Diag(SelLoc, diag::warn_undeclared_selector) << Sel; QualType Ty = Context.getObjCSelType(); - return new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc); + ObjCSelectorExpr *E = + new (Context) ObjCSelectorExpr(Ty, Sel, AtLoc, RParenLoc); + // Make sure that we have seen this selector. There are lots of checks we + // should be doing on this selector. For example, when this is passed as the + // second argument to objc_msgSend() on the Mac runtime, or as the selector + // argument to the -performSelector:. We can do these checks at run time + // with the GNU runtimes, but the Apple runtimes let you sneak stack + // corruption in easily by passing the wrong selector to these functions if + // there is no static checking. + // + // Only log a warning on the GNU runtime. + E->setMethodDecl(LookupInstanceMethodInGlobalPool(Sel, + SourceRange(LParenLoc, LParenLoc), !LangOpts.NeXTRuntime)); + return E; } Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, |