forked from OSchip/llvm-project
[ObjC] Remove _Atomic from return type and parameter type of
objective-c properties. This fixes an assert in CodeGen that fires when the getter and setter functions for an objective-c property of type _Atomic(_Bool) are synthesized. rdar://problem/26322972 Differential Revision: http://reviews.llvm.org/D20407 llvm-svn: 270808
This commit is contained in:
parent
deb27681d7
commit
de6f25f6a3
|
@ -1080,6 +1080,9 @@ public:
|
|||
/// Strip Objective-C "__kindof" types from the given type.
|
||||
QualType stripObjCKindOfType(const ASTContext &ctx) const;
|
||||
|
||||
/// Remove all qualifiers including _Atomic.
|
||||
QualType getAtomicUnqualifiedType() const;
|
||||
|
||||
private:
|
||||
// These methods are implemented in a separate translation unit;
|
||||
// "static"-ize them to avoid creating temporary QualTypes in the
|
||||
|
|
|
@ -1274,6 +1274,12 @@ QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const {
|
|||
});
|
||||
}
|
||||
|
||||
QualType QualType::getAtomicUnqualifiedType() const {
|
||||
if (auto AT = getTypePtr()->getAs<AtomicType>())
|
||||
return AT->getValueType().getUnqualifiedType();
|
||||
return getUnqualifiedType();
|
||||
}
|
||||
|
||||
Optional<ArrayRef<QualType>> Type::getObjCSubstitutions(
|
||||
const DeclContext *dc) const {
|
||||
// Look through method scopes.
|
||||
|
|
|
@ -897,9 +897,8 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||
|
||||
// Currently, all atomic accesses have to be through integer
|
||||
// types, so there's no point in trying to pick a prettier type.
|
||||
llvm::Type *bitcastType =
|
||||
llvm::Type::getIntNTy(getLLVMContext(),
|
||||
getContext().toBits(strategy.getIvarSize()));
|
||||
uint64_t ivarSize = getContext().toBits(strategy.getIvarSize());
|
||||
llvm::Type *bitcastType = llvm::Type::getIntNTy(getLLVMContext(), ivarSize);
|
||||
bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay
|
||||
|
||||
// Perform an atomic load. This does not impose ordering constraints.
|
||||
|
@ -911,7 +910,16 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||
// Store that value into the return address. Doing this with a
|
||||
// bitcast is likely to produce some pretty ugly IR, but it's not
|
||||
// the *most* terrible thing in the world.
|
||||
Builder.CreateStore(load, Builder.CreateBitCast(ReturnValue, bitcastType));
|
||||
llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
|
||||
uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
|
||||
llvm::Value *ivarVal = load;
|
||||
if (ivarSize > retTySize) {
|
||||
llvm::Type *newTy = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
|
||||
ivarVal = Builder.CreateTrunc(load, newTy);
|
||||
bitcastType = newTy->getPointerTo();
|
||||
}
|
||||
Builder.CreateStore(ivarVal,
|
||||
Builder.CreateBitCast(ReturnValue, bitcastType));
|
||||
|
||||
// Make sure we don't do an autorelease.
|
||||
AutoreleaseResult = false;
|
||||
|
@ -1010,7 +1018,6 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
|
|||
AutoreleaseResult = false;
|
||||
}
|
||||
|
||||
value = Builder.CreateBitCast(value, ConvertType(propType));
|
||||
value = Builder.CreateBitCast(
|
||||
value, ConvertType(GetterMethodDecl->getReturnType()));
|
||||
}
|
||||
|
|
|
@ -1493,24 +1493,26 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
|
|||
if (!GetterMethod)
|
||||
return false;
|
||||
QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
|
||||
QualType PropertyIvarType = property->getType().getNonReferenceType();
|
||||
bool compat = Context.hasSameType(PropertyIvarType, GetterType);
|
||||
QualType PropertyRValueType =
|
||||
property->getType().getNonReferenceType().getAtomicUnqualifiedType();
|
||||
bool compat = Context.hasSameType(PropertyRValueType, GetterType);
|
||||
if (!compat) {
|
||||
const ObjCObjectPointerType *propertyObjCPtr = nullptr;
|
||||
const ObjCObjectPointerType *getterObjCPtr = nullptr;
|
||||
if ((propertyObjCPtr = PropertyIvarType->getAs<ObjCObjectPointerType>()) &&
|
||||
if ((propertyObjCPtr =
|
||||
PropertyRValueType->getAs<ObjCObjectPointerType>()) &&
|
||||
(getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))
|
||||
compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);
|
||||
else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType)
|
||||
else if (CheckAssignmentConstraints(Loc, GetterType, PropertyRValueType)
|
||||
!= Compatible) {
|
||||
Diag(Loc, diag::error_property_accessor_type)
|
||||
<< property->getDeclName() << PropertyIvarType
|
||||
<< property->getDeclName() << PropertyRValueType
|
||||
<< GetterMethod->getSelector() << GetterType;
|
||||
Diag(GetterMethod->getLocation(), diag::note_declared_at);
|
||||
return true;
|
||||
} else {
|
||||
compat = true;
|
||||
QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
|
||||
QualType lhsType = Context.getCanonicalType(PropertyRValueType);
|
||||
QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
|
||||
if (lhsType != rhsType && lhsType->isArithmeticType())
|
||||
compat = false;
|
||||
|
@ -2204,8 +2206,11 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
|
|||
// for this class.
|
||||
SourceLocation Loc = property->getLocation();
|
||||
|
||||
// The getter returns the declared property type with all qualifiers
|
||||
// removed.
|
||||
QualType resultTy = property->getType().getAtomicUnqualifiedType();
|
||||
|
||||
// If the property is null_resettable, the getter returns nonnull.
|
||||
QualType resultTy = property->getType();
|
||||
if (property->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_null_resettable) {
|
||||
QualType modifiedTy = resultTy;
|
||||
|
@ -2274,9 +2279,12 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
|
|||
ObjCMethodDecl::Optional :
|
||||
ObjCMethodDecl::Required);
|
||||
|
||||
// Remove all qualifiers from the setter's parameter type.
|
||||
QualType paramTy =
|
||||
property->getType().getUnqualifiedType().getAtomicUnqualifiedType();
|
||||
|
||||
// If the property is null_resettable, the setter accepts a
|
||||
// nullable value.
|
||||
QualType paramTy = property->getType().getUnqualifiedType();
|
||||
if (property->getPropertyAttributes() &
|
||||
ObjCPropertyDecl::OBJC_PR_null_resettable) {
|
||||
QualType modifiedTy = paramTy;
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-macosx10 -emit-llvm -x objective-c %s -o - | FileCheck %s
|
||||
|
||||
// CHECK: define internal zeroext i1 @"\01-[A0 p]"(
|
||||
// CHECK: %[[ATOMIC_LOAD:.*]] = load atomic i8, i8* %{{.*}} seq_cst
|
||||
// CHECK: %[[TOBOOL:.*]] = trunc i8 %[[ATOMIC_LOAD]] to i1
|
||||
// CHECK: ret i1 %[[TOBOOL]]
|
||||
|
||||
// CHECK: define internal void @"\01-[A0 setP:]"({{.*}} i1 zeroext {{.*}})
|
||||
// CHECK: store atomic i8 %{{.*}}, i8* %{{.*}} seq_cst
|
||||
// CHECK: ret void
|
||||
|
||||
// CHECK: define internal zeroext i1 @"\01-[A1 p]"(
|
||||
// CHECK: %[[ATOMIC_LOAD:.*]] = load atomic i8, i8* %{{.*}} unordered
|
||||
// CHECK: %[[TOBOOL:.*]] = trunc i8 %load to i1
|
||||
// CHECK: ret i1 %[[TOBOOL]]
|
||||
|
||||
// CHECK: define internal void @"\01-[A1 setP:]"({{.*}} i1 zeroext %p)
|
||||
// CHECK: store atomic i8 %{{.*}}, i8* %{{.*}} unordered
|
||||
// CHECK: ret void
|
||||
|
||||
@interface A0
|
||||
@property(nonatomic) _Atomic(_Bool) p;
|
||||
@end
|
||||
@implementation A0
|
||||
@end
|
||||
|
||||
@interface A1 {
|
||||
_Atomic(_Bool) p;
|
||||
}
|
||||
@property _Atomic(_Bool) p;
|
||||
@end
|
||||
@implementation A1
|
||||
@synthesize p;
|
||||
@end
|
|
@ -0,0 +1,61 @@
|
|||
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10 -ast-dump "%s" 2>&1 | FileCheck %s
|
||||
|
||||
// CHECK: TypedefDecl {{.*}} referenced AtomicBool '_Atomic(_Bool)'
|
||||
// CHECK: AtomicType {{.*}} '_Atomic(_Bool)'
|
||||
// CHECK: BuiltinType {{.*}} '_Bool'
|
||||
// CHECK: ObjCInterfaceDecl {{.*}} A0
|
||||
// CHECK: ObjCPropertyDecl {{.*}} p '_Atomic(_Bool)' {{.*}} nonatomic
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - p '_Bool'
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - setP: 'void'
|
||||
// CHECK: ParmVarDecl {{.*}} p '_Bool'
|
||||
// CHECK: ObjCInterfaceDecl {{.*}} A1
|
||||
// CHECK: ObjCPropertyDecl {{.*}} p 'AtomicBool':'_Atomic(_Bool)' {{.*}} nonatomic
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - p '_Bool'
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - setP: 'void'
|
||||
// CHECK: ParmVarDecl {{.*}} p '_Bool'
|
||||
// CHECK: ObjCInterfaceDecl {{.*}} A2
|
||||
// CHECK: ObjCIvarDecl {{.*}} p '_Atomic(_Bool)' protected
|
||||
// CHECK: ObjCPropertyDecl {{.*}} p '_Atomic(_Bool)'
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - p '_Bool'
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - setP: 'void'
|
||||
// CHECK: ParmVarDecl {{.*}} p '_Bool'
|
||||
// CHECK: ObjCInterfaceDecl {{.*}} A3
|
||||
// CHECK: ObjCIvarDecl {{.*}} p 'AtomicBool':'_Atomic(_Bool)' protected
|
||||
// CHECK: ObjCPropertyDecl {{.*}} p 'AtomicBool':'_Atomic(_Bool)'
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - p '_Bool'
|
||||
// CHECK: ObjCMethodDecl {{.*}} implicit - setP: 'void'
|
||||
// CHECK: ParmVarDecl {{.*}} p '_Bool'
|
||||
|
||||
typedef _Atomic(_Bool) AtomicBool;
|
||||
|
||||
@interface A0
|
||||
@property(nonatomic) _Atomic(_Bool) p;
|
||||
@end
|
||||
@implementation A0
|
||||
@end
|
||||
|
||||
@interface A1
|
||||
@property(nonatomic) AtomicBool p;
|
||||
@end
|
||||
@implementation A1
|
||||
@end
|
||||
|
||||
@interface A2 {
|
||||
_Atomic(_Bool) p;
|
||||
}
|
||||
@property _Atomic(_Bool) p;
|
||||
@end
|
||||
|
||||
@implementation A2
|
||||
@synthesize p;
|
||||
@end
|
||||
|
||||
@interface A3 {
|
||||
AtomicBool p;
|
||||
}
|
||||
@property AtomicBool p;
|
||||
@end
|
||||
|
||||
@implementation A3
|
||||
@synthesize p;
|
||||
@end
|
Loading…
Reference in New Issue