aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2019-02-18 09:33:35 +0000
committerHans Wennborg <hans@hanshq.net>2019-02-18 09:33:35 +0000
commit389b70774d135b175f468fb42b6e7570039c9136 (patch)
tree3ceca33ab002b662251e4ab33ec155f9a7d82860
parentc484df6c4d82f395d38f814ada9f7b7447727a51 (diff)
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 ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/release_80@354248 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/CodeGen/CGDecl.cpp14
-rw-r--r--test/CodeGenCXX/trivial-auto-var-init.cpp31
2 files changed, 33 insertions, 12 deletions
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index b98657ffd8..790a8df3d7 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -1620,8 +1620,9 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
bool capturedByInit =
Init && emission.IsEscapingByRef && isCapturedBy(D, Init);
- Address Loc =
- capturedByInit ? emission.Addr : emission.getObjectAddress(*this);
+ bool locIsByrefHeader = !capturedByInit;
+ const Address Loc =
+ locIsByrefHeader ? emission.getObjectAddress(*this) : emission.Addr;
// Note: constexpr already initializes everything correctly.
LangOptions::TrivialAutoVarInitKind trivialAutoVarInit =
@@ -1637,7 +1638,7 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
return;
// Only initialize a __block's storage: we always initialize the header.
- if (emission.IsEscapingByRef)
+ if (emission.IsEscapingByRef && !locIsByrefHeader)
Loc = emitBlockByrefAddress(Loc, &D, /*follow=*/false);
CharUnits Size = getContext().getTypeSizeInChars(type);
@@ -1745,10 +1746,9 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) {
}
llvm::Type *BP = CGM.Int8Ty->getPointerTo(Loc.getAddressSpace());
- if (Loc.getType() != BP)
- Loc = Builder.CreateBitCast(Loc, BP);
-
- emitStoresForConstant(CGM, D, Loc, isVolatile, Builder, constant);
+ emitStoresForConstant(
+ CGM, D, (Loc.getType() == BP) ? Loc : Builder.CreateBitCast(Loc, BP),
+ isVolatile, Builder, constant);
}
/// Emit an expression as an initializer for an object (variable, field, etc.)
diff --git a/test/CodeGenCXX/trivial-auto-var-init.cpp b/test/CodeGenCXX/trivial-auto-var-init.cpp
index 37ff770abf..0a9ad86c7e 100644
--- a/test/CodeGenCXX/trivial-auto-var-init.cpp
+++ b/test/CodeGenCXX/trivial-auto-var-init.cpp
@@ -45,14 +45,35 @@ void test_block() {
// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured, %struct.__block_byref_captured* %captured, i32 0, i32 4
// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8
// PATTERN: %call = call %struct.XYZ* @create(
+using Block = void (^)();
+typedef struct XYZ {
+ Block block;
+} * xyz_t;
void test_block_self_init() {
- using Block = void (^)();
- typedef struct XYZ {
- Block block;
- } * xyz_t;
extern xyz_t create(Block block);
__block xyz_t captured = create(^() {
- (void)captured;
+ used(captured);
+ });
+}
+
+// Capturing with escape after initialization is also an edge case.
+//
+// UNINIT-LABEL: test_block_captures_self_after_init(
+// ZERO-LABEL: test_block_captures_self_after_init(
+// ZERO: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
+// ZERO: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4
+// ZERO-NEXT: store %struct.XYZ* null, %struct.XYZ** %captured1, align 8
+// ZERO: %call = call %struct.XYZ* @create(
+// PATTERN-LABEL: test_block_captures_self_after_init(
+// PATTERN: %block = alloca <{ i8*, i32, i32, i8*, %struct.__block_descriptor*, i8* }>, align 8
+// PATTERN: %captured1 = getelementptr inbounds %struct.__block_byref_captured.1, %struct.__block_byref_captured.1* %captured, i32 0, i32 4
+// PATTERN-NEXT: store %struct.XYZ* inttoptr (i64 -6148914691236517206 to %struct.XYZ*), %struct.XYZ** %captured1, align 8
+// PATTERN: %call = call %struct.XYZ* @create(
+void test_block_captures_self_after_init() {
+ extern xyz_t create(Block block);
+ __block xyz_t captured;
+ captured = create(^() {
+ used(captured);
});
}