aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ExprObjC.h8
-rw-r--r--lib/AST/Expr.cpp1
-rw-r--r--lib/CodeGen/CGExprConstant.cpp8
-rw-r--r--lib/CodeGen/CGObjC.cpp6
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp61
-rw-r--r--lib/CodeGen/CGObjCMac.cpp8
-rw-r--r--lib/CodeGen/CGObjCRuntime.h6
-rw-r--r--lib/Sema/SemaExprObjC.cpp15
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,