Skip to content

Commit 1b04bdc

Browse files
committed
[SEH] capture 'this'
Simply make sure that the CodeGenFunction::CXXThisValue and CXXABIThisValue are correctly initialized to the recovered value. For lambda capture, we also need to make sure to fill the LambdaCaptureFields Differential Revision: https://reviews.llvm.org/D97534
1 parent 53dacb7 commit 1b04bdc

File tree

2 files changed

+67
-19
lines changed

2 files changed

+67
-19
lines changed

clang/lib/CodeGen/CGException.cpp

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1702,10 +1702,8 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
17021702

17031703
void VisitDeclRefExpr(const DeclRefExpr *E) {
17041704
// If this is already a capture, just make sure we capture 'this'.
1705-
if (E->refersToEnclosingVariableOrCapture()) {
1705+
if (E->refersToEnclosingVariableOrCapture())
17061706
Captures.insert(ParentThis);
1707-
return;
1708-
}
17091707

17101708
const auto *D = dyn_cast<VarDecl>(E->getDecl());
17111709
if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())
@@ -1865,27 +1863,34 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
18651863

18661864
// Create llvm.localrecover calls for all captures.
18671865
for (const VarDecl *VD : Finder.Captures) {
1868-
if (isa<ImplicitParamDecl>(VD)) {
1869-
CGM.ErrorUnsupported(VD, "'this' captured by SEH");
1870-
CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType()));
1871-
continue;
1872-
}
18731866
if (VD->getType()->isVariablyModifiedType()) {
18741867
CGM.ErrorUnsupported(VD, "VLA captured by SEH");
18751868
continue;
18761869
}
18771870
assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
18781871
"captured non-local variable");
18791872

1873+
auto L = ParentCGF.LambdaCaptureFields.find(VD);
1874+
if (L != ParentCGF.LambdaCaptureFields.end()) {
1875+
LambdaCaptureFields[VD] = L->second;
1876+
continue;
1877+
}
1878+
18801879
// If this decl hasn't been declared yet, it will be declared in the
18811880
// OutlinedStmt.
18821881
auto I = ParentCGF.LocalDeclMap.find(VD);
18831882
if (I == ParentCGF.LocalDeclMap.end())
18841883
continue;
18851884

18861885
Address ParentVar = I->second;
1887-
setAddrOfLocalVar(
1888-
VD, recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP));
1886+
Address Recovered =
1887+
recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);
1888+
setAddrOfLocalVar(VD, Recovered);
1889+
1890+
if (isa<ImplicitParamDecl>(VD)) {
1891+
CXXThisValue = Builder.CreateLoad(Recovered, "this");
1892+
CXXABIThisValue = CXXThisValue;
1893+
}
18891894
}
18901895

18911896
if (Finder.SEHCodeSlot.isValid()) {

clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,44 +39,87 @@ void S::test_method() {
3939
int l1 = 13;
4040
__try {
4141
might_crash();
42-
} __except(basic_filter(l1)) {
43-
// FIXME: Test capturing 'this' and 'm1'.
42+
} __except (basic_filter(l1, m1)) {
4443
}
4544
}
4645

4746
// CHECK-LABEL: define dso_local void @"?test_method@S@@QEAAXXZ"(%struct.S* {{[^,]*}} %this)
48-
// CHECK: @llvm.localescape(i32* %[[l1_addr:[^, ]*]])
47+
// CHECK: @llvm.localescape(i32* %[[l1_addr:[^, ]*]], %struct.S** %[[this_addr:[^, ]*]])
48+
// CHECK: store %struct.S* %this, %struct.S** %[[this_addr]], align 8
4949
// CHECK: store i32 13, i32* %[[l1_addr]], align 4
5050
// CHECK: invoke void @might_crash()
5151

5252
// CHECK-LABEL: define internal i32 @"?filt$0@0@test_method@S@@"(i8* %exception_pointers, i8* %frame_pointer)
5353
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (%struct.S*)* @"?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer)
5454
// CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"?test_method@S@@QEAAXXZ" to i8*), i8* %[[fp]], i32 0)
5555
// CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32*
56+
// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"?test_method@S@@QEAAXXZ" to i8*), i8* %[[fp]], i32 1)
57+
// CHECK: %[[this_ptr:[^ ]*]] = bitcast i8* %[[this_i8]] to %struct.S**
58+
// CHECK: %[[this:[^ ]*]] = load %struct.S*, %struct.S** %[[this_ptr]], align 8
59+
// CHECK: %[[m1_ptr:[^ ]*]] = getelementptr inbounds %struct.S, %struct.S* %[[this]], i32 0, i32 0
60+
// CHECK: %[[m1:[^ ]*]] = load i32, i32* %[[m1_ptr]]
5661
// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]]
57-
// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]])
62+
// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]], i32 %[[m1]])
63+
64+
struct V {
65+
void test_virtual(int p1);
66+
virtual void virt(int p1);
67+
};
68+
69+
void V::test_virtual(int p1) {
70+
__try {
71+
might_crash();
72+
} __finally {
73+
virt(p1);
74+
}
75+
}
76+
77+
// CHECK-LABEL: define dso_local void @"?test_virtual@V@@QEAAXH@Z"(%struct.V* {{[^,]*}} %this, i32 %p1)
78+
// CHECK: @llvm.localescape(%struct.V** %[[this_addr:[^, ]*]], i32* %[[p1_addr:[^, ]*]])
79+
// CHECK: store i32 %p1, i32* %[[p1_addr]], align 4
80+
// CHECK: store %struct.V* %this, %struct.V** %[[this_addr]], align 8
81+
// CHECK: invoke void @might_crash()
82+
83+
// CHECK-LABEL: define internal void @"?fin$0@0@test_virtual@V@@"(i8 %abnormal_termination, i8* %frame_pointer)
84+
// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.V*, i32)* @"?test_virtual@V@@QEAAXH@Z" to i8*), i8* %frame_pointer, i32 0)
85+
// CHECK: %[[this_ptr:[^ ]*]] = bitcast i8* %[[this_i8]] to %struct.V**
86+
// CHECK: %[[this:[^ ]*]] = load %struct.V*, %struct.V** %[[this_ptr]], align 8
87+
// CHECK: %[[p1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.V*, i32)* @"?test_virtual@V@@QEAAXH@Z" to i8*), i8* %frame_pointer, i32 1)
88+
// CHECK: %[[p1_ptr:[^ ]*]] = bitcast i8* %[[p1_i8]] to i32*
89+
// CHECK: %[[p1:[^ ]*]] = load i32, i32* %[[p1_ptr]]
90+
// CHECK: %[[this_2:[^ ]*]] = bitcast %struct.V* %[[this]] to void (%struct.V*, i32)***
91+
// CHECK: %[[vtable:[^ ]*]] = load void (%struct.V*, i32)**, void (%struct.V*, i32)*** %[[this_2]], align 8
92+
// CHECK: %[[vfn:[^ ]*]] = getelementptr inbounds void (%struct.V*, i32)*, void (%struct.V*, i32)** %[[vtable]], i64 0
93+
// CHECK: %[[virt:[^ ]*]] = load void (%struct.V*, i32)*, void (%struct.V*, i32)** %[[vfn]], align 8
94+
// CHECK: call void %[[virt]](%struct.V* {{[^,]*}} %[[this]], i32 %[[p1]])
5895

5996
void test_lambda() {
6097
int l1 = 13;
6198
auto lambda = [&]() {
6299
int l2 = 42;
63100
__try {
64101
might_crash();
65-
} __except(basic_filter(l2)) {
66-
// FIXME: Test 'l1' when we can capture the lambda's 'this' decl.
102+
} __except (basic_filter(l1, l2)) {
67103
}
68104
};
69105
lambda();
70106
}
71107

72108
// CHECK-LABEL: define internal void @"??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ"(%class.anon* {{[^,]*}} %this)
73-
// CHECK: @llvm.localescape(i32* %[[l2_addr:[^, ]*]])
109+
// CHECK: @llvm.localescape(%class.anon** %[[this_addr:[^, ]*]], i32* %[[l2_addr:[^, ]*]])
110+
// CHECK: store %class.anon* %this, %class.anon** %[[this_addr]], align 8
74111
// CHECK: store i32 42, i32* %[[l2_addr]], align 4
75112
// CHECK: invoke void @might_crash()
76113

77114
// CHECK-LABEL: define internal i32 @"?filt$0@0@?R<lambda_0>@?0??test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer)
78115
// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %frame_pointer)
79-
// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 0)
116+
// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 0)
117+
// CHECK: %[[this_ptr:[^ ]*]] = bitcast i8* %[[this_i8]] to %class.anon**
118+
// CHECK: %[[this:[^ ]*]] = load %class.anon*, %class.anon** %[[this_ptr]], align 8
119+
// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 1)
80120
// CHECK: %[[l2_ptr:[^ ]*]] = bitcast i8* %[[l2_i8]] to i32*
81121
// CHECK: %[[l2:[^ ]*]] = load i32, i32* %[[l2_ptr]]
82-
// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l2]])
122+
// CHECK: %[[l1_ref_ptr:[^ ]*]] = getelementptr inbounds %class.anon, %class.anon* %[[this]], i32 0, i32 0
123+
// CHECK: %[[l1_ref:[^ ]*]] = load i32*, i32** %[[l1_ref_ptr]]
124+
// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ref]]
125+
// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]], i32 %[[l2]])

0 commit comments

Comments
 (0)