From: Akira Hatanaka Date: Thu, 26 May 2016 00:37:30 +0000 (+0000) Subject: [ObjC] Remove _Atomic from return type and parameter type of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9793769423cdfcaf5fcf1b4f05c61230407f108f;p=clang [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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@270808 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index a68be969eb..05650c93ac 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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 diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 0e5f0b256e..6dc585bf29 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1274,6 +1274,12 @@ QualType QualType::stripObjCKindOfType(const ASTContext &constCtx) const { }); } +QualType QualType::getAtomicUnqualifiedType() const { + if (auto AT = getTypePtr()->getAs()) + return AT->getValueType().getUnqualifiedType(); + return getUnqualifiedType(); +} + Optional> Type::getObjCSubstitutions( const DeclContext *dc) const { // Look through method scopes. diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 7fb6a36590..5aa549b8a9 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -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())); } diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index f9c495d641..5e38751f44 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -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()) && + if ((propertyObjCPtr = + PropertyRValueType->getAs()) && (getterObjCPtr = GetterType->getAs())) 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; diff --git a/test/CodeGenObjC/property-atomic-bool.m b/test/CodeGenObjC/property-atomic-bool.m new file mode 100644 index 0000000000..77da129f6c --- /dev/null +++ b/test/CodeGenObjC/property-atomic-bool.m @@ -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 diff --git a/test/SemaObjC/property-atomic-bool.m b/test/SemaObjC/property-atomic-bool.m new file mode 100644 index 0000000000..20bb607f79 --- /dev/null +++ b/test/SemaObjC/property-atomic-bool.m @@ -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