Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -2446,21 +2446,37 @@ EHStack.pushCleanup(NormalCleanup, Ptr); } +static bool shouldRetainObjCLifetime(Qualifiers::ObjCLifetime Lifetime) { + switch (Lifetime) { + case Qualifiers::OCL_None: + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Strong: + case Qualifiers::OCL_Autoreleasing: + return true; + + case Qualifiers::OCL_Weak: + return false; + } + + llvm_unreachable("impossible lifetime!"); +} + static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, LValue lvalue, QualType type) { + bool SuppressResultRetain = !shouldRetainObjCLifetime(type.getObjCLifetime()); switch (type.getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Strong: case Qualifiers::OCL_Autoreleasing: - return TryEmitResult(CGF.EmitLoadOfLValue(lvalue, - SourceLocation()).getScalarVal(), - false); + return TryEmitResult( + CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal(), + SuppressResultRetain); case Qualifiers::OCL_Weak: return TryEmitResult(CGF.EmitARCLoadWeakRetained(lvalue.getAddress()), - true); + SuppressResultRetain); } llvm_unreachable("impossible lifetime!"); @@ -2500,6 +2516,17 @@ cast(e)->getOpcode() == BO_Assign) return TryEmitResult(CGF.EmitScalarExpr(e), false); + // DeclRefExpr referencing non-odr-used variable might be constant-evaluated + // and in this case we don't have l-value. Emit code for scalar expression + // instead of emitting LValue and loading it. + if (const auto *DRE = dyn_cast(e)) { + const ValueDecl *Decl = DRE->getDecl(); + if (isa(Decl) && !Decl->isUsed(false) && + !Decl->getType()->isReferenceType()) + return TryEmitResult(CGF.EmitScalarExpr(e), + !shouldRetainObjCLifetime(type.getObjCLifetime())); + } + return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type); } Index: clang/test/CodeGenObjCXX/arc-constexpr.mm =================================================================== --- clang/test/CodeGenObjCXX/arc-constexpr.mm +++ clang/test/CodeGenObjCXX/arc-constexpr.mm @@ -1,18 +1,50 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -o - -std=c++11 %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fobjc-arc -fobjc-runtime-has-weak -o - -std=c++11 %s | FileCheck %s // CHECK: %[[TYPE:[a-z0-9]+]] = type opaque // CHECK: @[[CFSTRING:[a-z0-9_]+]] = private global %struct.__NSConstantString_tag +@class NSString; -// CHECK: define void @_Z5test1v +// CHECK-LABEL: define void @_Z5test1v // CHECK: %[[ALLOCA:[A-Z]+]] = alloca %[[TYPE]]* // CHECK: %[[V0:[0-9]+]] = call i8* @objc_retain(i8* bitcast (%struct.__NSConstantString_tag* @[[CFSTRING]] // CHECK: %[[V1:[0-9]+]] = bitcast i8* %[[V0]] to %[[TYPE]]* // CHECK: store %[[TYPE]]* %[[V1]], %[[TYPE]]** %[[ALLOCA]] // CHECK: %[[V2:[0-9]+]] = bitcast %[[TYPE]]** %[[ALLOCA]] // CHECK: call void @objc_storeStrong(i8** %[[V2]], i8* null) - -@class NSString; - void test1() { constexpr NSString *S = @"abc"; } + +// CHECK-LABEL: define void @_Z5test2v +// CHECK: %[[CONST:[a-zA-Z]+]] = alloca %[[TYPE]]* +// CHECK: %[[REF_CONST:[a-zA-Z]+]] = alloca %[[TYPE]]* +// CHECK: %[[V0:[0-9]+]] = call i8* @objc_retain(i8* bitcast (%struct.__NSConstantString_tag* @[[CFSTRING]] +// CHECK-NEXT: %[[V1:[0-9]+]] = bitcast i8* %[[V0]] to %[[TYPE]]* +// CHECK-NEXT: store %[[TYPE]]* %[[V1]], %[[TYPE]]** %[[CONST]] +// CHECK: %[[V2:[0-9]+]] = call i8* @objc_retain(i8* bitcast (%struct.__NSConstantString_tag* @[[CFSTRING]] +// CHECK-NEXT: %[[V3:[0-9]+]] = bitcast i8* %[[V2]] to %[[TYPE]]* +// CHECK-NEXT: store %[[TYPE]]* %[[V3]], %[[TYPE]]** %[[REF_CONST]] +// CHECK: %[[V4:[0-9]+]] = bitcast %[[TYPE]]** %[[REF_CONST]] +// CHECK-NEXT: call void @objc_storeStrong(i8** %[[V4]], i8* null) +// CHECK: %[[V5:[0-9]+]] = bitcast %[[TYPE]]** %[[CONST]] +// CHECK-NEXT: call void @objc_storeStrong(i8** %[[V5]], i8* null) +void test2() { + constexpr NSString *Const = @"abc"; + // Initialize RefConst with Const initializer instead of reading from variable. + NSString* RefConst = Const; +} + +// CHECK-LABEL: define void @_Z5test3v +// CHECK: %[[WEAK_CONST:[a-zA-Z]+]] = alloca %[[TYPE]]* +// CHECK: %[[REF_WEAK_CONST:[a-zA-Z]+]] = alloca %[[TYPE]]* +// CHECK: %[[V0:[0-9]+]] = bitcast %[[TYPE]]** %[[WEAK_CONST]] +// CHECK-NEXT: %[[V1:[0-9]+]] = call i8* @objc_initWeak(i8** %[[V0]], i8* bitcast (%struct.__NSConstantString_tag* @[[CFSTRING]] +// CHECK: store %[[TYPE]]* bitcast (%struct.__NSConstantString_tag* @[[CFSTRING]] to %[[TYPE]]*), %[[TYPE]]** %[[REF_WEAK_CONST]] +// CHECK: %[[V2:[0-9]+]] = bitcast %[[TYPE]]** %[[REF_WEAK_CONST]] +// CHECK-NEXT: call void @objc_storeStrong(i8** %[[V2]], i8* null) +// CHECK: %[[V3:[0-9]+]] = bitcast %[[TYPE]]** %[[WEAK_CONST]] +// CHECK-NEXT: call void @objc_destroyWeak(i8** %[[V3]]) +void test3() { + __weak constexpr NSString *WeakConst = @"abc"; + NSString* RefWeakConst = WeakConst; +}