/// 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
});
}
+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.
// 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.
// 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;
AutoreleaseResult = false;
}
- value = Builder.CreateBitCast(value, ConvertType(propType));
value = Builder.CreateBitCast(
value, ConvertType(GetterMethodDecl->getReturnType()));
}
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;
// 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;
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;
--- /dev/null
+// 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
--- /dev/null
+// 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