diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1189,8 +1189,17 @@ // Return (ivar-type) objc_getProperty((id) self, _cmd, offset, true). // FIXME: Can't this be simpler? This might even be worse than the // corresponding gcc code. - llvm::Value *cmd = - Builder.CreateLoad(GetAddrOfLocalVar(getterMethod->getCmdDecl()), "cmd"); + llvm::Value *cmd; + if (getterMethod->isDirectMethod()) { + // Direct methods do not have the `_cmd` parameter; the selector must be + // loaded explicitly. Since it is not otherwise used in the getter, there + // is no reason to create a local variable for it. + cmd = + CGM.getObjCRuntime().GetSelector(*this, getterMethod->getSelector()); + } else { + cmd = Builder.CreateLoad(GetAddrOfLocalVar(getterMethod->getCmdDecl()), + "cmd"); + } llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy); llvm::Value *ivarOffset = EmitIvarOffset(classImpl->getClassInterface(), ivar); @@ -1475,10 +1484,18 @@ // Emit objc_setProperty((id) self, _cmd, offset, arg, // , ). - llvm::Value *cmd = - Builder.CreateLoad(GetAddrOfLocalVar(setterMethod->getCmdDecl())); - llvm::Value *self = - Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy); + llvm::Value *cmd; + if (setterMethod->isDirectMethod()) { + // Direct methods do not have the `_cmd` parameter; the selector must be + // loaded explicitly. Since it is not otherwise used in the setter, there + // is no reason to create a local variable for it. + cmd = + CGM.getObjCRuntime().GetSelector(*this, setterMethod->getSelector()); + } else { + cmd = Builder.CreateLoad(GetAddrOfLocalVar(setterMethod->getCmdDecl()), + "cmd"); + } + llvm::Value *self = Builder.CreateBitCast(LoadObjCSelf(), VoidPtrTy); llvm::Value *ivarOffset = EmitIvarOffset(classImpl->getClassInterface(), ivar); Address argAddr = GetAddrOfLocalVar(*setterMethod->param_begin()); diff --git a/clang/test/CodeGenObjC/direct-method.m b/clang/test/CodeGenObjC/direct-method.m --- a/clang/test/CodeGenObjC/direct-method.m +++ b/clang/test/CodeGenObjC/direct-method.m @@ -14,6 +14,7 @@ - (int)getInt __attribute__((objc_direct)); @property(direct, readonly) int intProperty; @property(direct, readonly) int intProperty2; +@property(direct, readonly) id objectProperty; @end @implementation Root @@ -167,6 +168,14 @@ @end // CHECK-LABEL: define hidden i32 @"\01-[Root intProperty]" +// Check the synthesized objectProperty calls objc_getProperty(); this also +// checks that the synthesized method accesses _cmd (or rather loads the +// selector, as it is an argument to objc_getProperty). +// CHECK-LABEL: define hidden i8* @"\01-[Root objectProperty]"( +// CHECK-LABEL: objc_direct_method.cont: +// CHECK-NEXT: load i8*, i8** @OBJC_SELECTOR_REFERENCES_ +// CHECK: call i8* @objc_getProperty({{.*}}) + @interface Foo : Root { id __strong _cause_cxx_destruct; }