diff options
| -rw-r--r-- | clang/include/clang/AST/Type.h | 3 | ||||
| -rw-r--r-- | clang/lib/AST/Type.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 17 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaObjCProperty.cpp | 24 | ||||
| -rw-r--r-- | clang/test/CodeGenObjC/property-atomic-bool.m | 34 | ||||
| -rw-r--r-- | clang/test/SemaObjC/property-atomic-bool.m | 61 | 
6 files changed, 132 insertions, 13 deletions
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index a68be969eb9..05650c93ac4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/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/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 0e5f0b256e4..6dc585bf296 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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. diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 7fb6a365902..5aa549b8a96 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index f9c495d6419..5e38751f44a 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/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<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; diff --git a/clang/test/CodeGenObjC/property-atomic-bool.m b/clang/test/CodeGenObjC/property-atomic-bool.m new file mode 100644 index 00000000000..77da129f6c0 --- /dev/null +++ b/clang/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/clang/test/SemaObjC/property-atomic-bool.m b/clang/test/SemaObjC/property-atomic-bool.m new file mode 100644 index 00000000000..20bb607f79c --- /dev/null +++ b/clang/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  | 

