From: Volodymyr Sapsai Date: Thu, 1 Nov 2018 22:50:08 +0000 (+0000) Subject: [CodeGen] Fix assertion on referencing constexpr Obj-C object with ARC. X-Git-Tag: llvmorg-8.0.0-rc1~5183 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8b286f99d4d39aa7847c85f00c111a577a354fef;p=platform%2Fupstream%2Fllvm.git [CodeGen] Fix assertion on referencing constexpr Obj-C object with ARC. Failed assertion is > Assertion failed: ((ND->isUsed(false) || !isa(ND) || !E->getLocation().isValid()) && "Should not use decl without marking it used!"), function EmitDeclRefLValue, file llvm-project/clang/lib/CodeGen/CGExpr.cpp, line 2437. `EmitDeclRefLValue` mentions > // A DeclRefExpr for a reference initialized by a constant expression can > // appear without being odr-used. Directly emit the constant initializer. The fix is to use the similar approach for non-references as for references. It is achieved by trying to emit a constant before we attempt to load non-odr-used variable as LValue. rdar://problem/40650504 Reviewers: ahatanak, rjmccall Reviewed By: rjmccall Subscribers: dexonsmith, erik.pilkington, cfe-commits Differential Revision: https://reviews.llvm.org/D53674 llvm-svn: 345903 --- diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 52bd364..73357f7 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -2447,27 +2447,36 @@ void CodeGenFunction::EmitObjCAutoreleasePoolCleanup(llvm::Value *Ptr) { 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(); QualType type = e->getType(); @@ -2501,6 +2510,16 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, cast(e)->getOpcode() == BO_Assign) return TryEmitResult(CGF.EmitScalarExpr(e), false); + // Try to emit code for scalar constant instead of emitting LValue and + // loading it because we are not guaranteed to have an l-value. One of such + // cases is DeclRefExpr referencing non-odr-used constant-evaluated variable. + if (const auto *decl_expr = dyn_cast(e)) { + auto *DRE = const_cast(decl_expr); + if (CodeGenFunction::ConstantEmission constant = CGF.tryEmitAsConstant(DRE)) + return TryEmitResult(CGF.emitScalarConstant(constant, DRE), + !shouldRetainObjCLifetime(type.getObjCLifetime())); + } + return tryEmitARCRetainLoadOfScalar(CGF, CGF.EmitLValue(e), type); } diff --git a/clang/test/CodeGenObjCXX/arc-constexpr.mm b/clang/test/CodeGenObjCXX/arc-constexpr.mm index 786e2cb..b12ff57 100644 --- a/clang/test/CodeGenObjCXX/arc-constexpr.mm +++ b/clang/test/CodeGenObjCXX/arc-constexpr.mm @@ -1,18 +1,51 @@ -// 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"; + // In IR RefConst should be initialized 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; +}