Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -1491,6 +1491,17 @@ return ConstantEmission(); } +llvm::Value * +CodeGenFunction::EmitConstant(const CodeGenFunction::ConstantEmission &Constant, + Expr *E) { + assert(Constant && "not a constant"); + if (Constant.isReference()) + return EmitLoadOfLValue(Constant.getReferenceLValue(*this, E), + E->getExprLoc()) + .getScalarVal(); + return Constant.getValue(); +} + llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue, SourceLocation Loc) { return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(), Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -456,19 +456,10 @@ return CGF.getOrCreateOpaqueRValueMapping(E).getScalarVal(); } - Value *emitConstant(const CodeGenFunction::ConstantEmission &Constant, - Expr *E) { - assert(Constant && "not a constant"); - if (Constant.isReference()) - return EmitLoadOfLValue(Constant.getReferenceLValue(CGF, E), - E->getExprLoc()); - return Constant.getValue(); - } - // l-values. Value *VisitDeclRefExpr(DeclRefExpr *E) { if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) - return emitConstant(Constant, E); + return CGF.EmitConstant(Constant, E); return EmitLoadOfLValue(E); } @@ -1545,7 +1536,7 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { if (CodeGenFunction::ConstantEmission Constant = CGF.tryEmitAsConstant(E)) { CGF.EmitIgnoredExpr(E->getBase()); - return emitConstant(Constant, E); + return CGF.EmitConstant(Constant, E); } else { llvm::APSInt Value; if (E->EvaluateAsInt(Value, CGF.getContext(), Expr::SE_AllowSideEffects)) { Index: clang/lib/CodeGen/CGObjC.cpp =================================================================== --- clang/lib/CodeGen/CGObjC.cpp +++ clang/lib/CodeGen/CGObjC.cpp @@ -2446,26 +2446,35 @@ EHStack.pushCleanup(NormalCleanup, Ptr); } -static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, - LValue lvalue, - QualType type) { - switch (type.getObjCLifetime()) { +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 TryEmitResult(CGF.EmitLoadOfLValue(lvalue, - SourceLocation()).getScalarVal(), - false); + return true; case Qualifiers::OCL_Weak: - return TryEmitResult(CGF.EmitARCLoadWeakRetained(lvalue.getAddress()), - true); + return false; } llvm_unreachable("impossible lifetime!"); } +static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, + LValue lvalue, + QualType type) { + llvm::Value *result; + bool shouldRetain = shouldRetainObjCLifetime(type.getObjCLifetime()); + if (shouldRetain) { + result = CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal(); + } else { + assert(type.getObjCLifetime() == Qualifiers::OCL_Weak); + result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress()); + } + return TryEmitResult(result, !shouldRetain); +} + static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, const Expr *e) { e = e->IgnoreParens(); @@ -2500,6 +2509,17 @@ cast(e)->getOpcode() == BO_Assign) return TryEmitResult(CGF.EmitScalarExpr(e), false); + // TODO: update comment when settled on implementation. + // 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 *decl_expr = dyn_cast(e)) { + auto *DRE = const_cast(decl_expr); + if (CodeGenFunction::ConstantEmission constant = CGF.tryEmitAsConstant(DRE)) + return TryEmitResult(CGF.EmitConstant(constant, DRE), + !shouldRetainObjCLifetime(type.getObjCLifetime())); + } + return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type); } Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -3524,6 +3524,7 @@ ConstantEmission tryEmitAsConstant(DeclRefExpr *refExpr); ConstantEmission tryEmitAsConstant(const MemberExpr *ME); + llvm::Value *EmitConstant(const ConstantEmission &Constant, Expr *E); RValue EmitPseudoObjectRValue(const PseudoObjectExpr *e, AggValueSlot slot = AggValueSlot::ignored()); 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; +}