Skip to content

Commit 07a7439

Browse files
committed
Merging r354147:
------------------------------------------------------------------------ r354147 | jfb | 2019-02-15 18:26:29 +0100 (Fri, 15 Feb 2019) | 27 lines Variable auto-init of blocks capturing self after init bugfix Summary: Blocks that capture themselves (and escape) after initialization currently codegen wrong because this: bool capturedByInit = Init && emission.IsEscapingByRef && isCapturedBy(D, Init); Address Loc = capturedByInit ? emission.Addr : emission.getObjectAddress(*this); Already adjusts Loc from thr alloca to a GEP. This code: if (emission.IsEscapingByRef) Loc = emitBlockByrefAddress(Loc, &D, /*follow=*/false); Was trying to do the same adjustment, and a GEP on a GEP (returning an int) triggers an assertion. <rdar://problem/47943027> Reviewers: ahatanak Subscribers: jkorous, dexonsmith, cfe-commits, rjmccall Tags: #clang Differential Revision: https://reviews.llvm.org/D58218 ------------------------------------------------------------------------ llvm-svn: 354248
1 parent a7da36b commit 07a7439

File tree

2 files changed

+33
-12
lines changed

2 files changed

+33
-12
lines changed

clang/lib/CodeGen/CGDecl.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,8 +1620,9 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
16201620
bool capturedByInit =
16211621
Init && emission.IsEscapingByRef && isCapturedBy(D, Init);
16221622

1623-
Address Loc =
1624-
capturedByInit ? emission.Addr : emission.getObjectAddress(*this);
1623+
bool locIsByrefHeader = !capturedByInit;
1624+
const Address Loc =
1625+
locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr;
16251626

16261627
// Note: constexpr already initializes everything correctly.
16271628
LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
@@ -1637,7 +1638,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
16371638
return;
16381639

16391640
// Only initialize a __block's storage: we always initialize the header.
1640-
if (emission.IsEscapingByRef)
1641+
if (emission.IsEscapingByRef && !locIsByrefHeader)
16411642
Loc = emitBlockByrefAddress(Loc, &D, /*follow=*/false);
16421643

16431644
CharUnits Size = getContext().getTypeSizeInChars(type);
@@ -1745,10 +1746,9 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
17451746
}
17461747

17471748
llvm::Type *BP = CGM.Int8Ty->getPointerTo(Loc.getAddressSpace());
1748-
if (Loc.getType() != BP)
1749-
Loc = Builder.CreateBitCast(Loc, BP);
1750-
1751-
emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant);
1749+
emitStoresForConstant(
1750+
CGM, D, (Loc.getType() == BP) ? Loc : Builder.CreateBitCast(Loc, BP),
1751+
isVolatile, Builder, constant);
17521752
}
17531753

17541754
/// Emit an expression as an initializer for an object (variable, field, etc.)

clang/test/CodeGenCXX/trivial-auto-var-init.cpp

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,35 @@ void test_block() {
4545
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4
4646
// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8
4747
// PATTERN: %call = call %struct.XYZ* @create(
48+
using Block = void (^)();
49+
typedef struct XYZ {
50+
Block block;
51+
} * xyz_t;
4852
void test_block_self_init() {
49-
using Block = void (^)();
50-
typedef struct XYZ {
51-
Block block;
52-
} * xyz_t;
5353
extern xyz_t create(Block block);
5454
__block xyz_t captured = create(^() {
55-
(void)captured;
55+
used(captured);
56+
});
57+
}
58+
59+
// Capturing with escape after initialization is also an edge case.
60+
//
61+
// UNINIT-LABEL: test_block_captures_self_after_init(
62+
// ZERO-LABEL: test_block_captures_self_after_init(
63+
// ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
64+
// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4
65+
// ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8
66+
// ZERO: %call = call %struct.XYZ* @create(
67+
// PATTERN-LABEL: test_block_captures_self_after_init(
68+
// PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
69+
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4
70+
// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8
71+
// PATTERN: %call = call %struct.XYZ* @create(
72+
void test_block_captures_self_after_init() {
73+
extern xyz_t create(Block block);
74+
__block xyz_t captured;
75+
captured = create(^() {
76+
used(captured);
5677
});
5778
}
5879

0 commit comments

Comments
 (0)