diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -1702,10 +1702,9 @@ void VisitDeclRefExpr(const DeclRefExpr *E) { // If this is already a capture, just make sure we capture 'this'. - if (E->refersToEnclosingVariableOrCapture()) { + if (E->refersToEnclosingVariableOrCapture()) Captures.insert(ParentThis); - return; - } + const auto *D = dyn_cast(E->getDecl()); if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage()) @@ -1865,11 +1864,6 @@ // Create llvm.localrecover calls for all captures. for (const VarDecl *VD : Finder.Captures) { - if (isa(VD)) { - CGM.ErrorUnsupported(VD, "'this' captured by SEH"); - CXXThisValue = llvm::UndefValue::get(ConvertTypeForMem(VD->getType())); - continue; - } if (VD->getType()->isVariablyModifiedType()) { CGM.ErrorUnsupported(VD, "VLA captured by SEH"); continue; @@ -1877,6 +1871,12 @@ assert((isa(VD) || VD->isLocalVarDeclOrParm()) && "captured non-local variable"); + auto L = ParentCGF.LambdaCaptureFields.find(VD); + if (L != ParentCGF.LambdaCaptureFields.end()) { + LambdaCaptureFields[VD] = L->second; + continue; + } + // If this decl hasn't been declared yet, it will be declared in the // OutlinedStmt. auto I = ParentCGF.LocalDeclMap.find(VD); @@ -1884,8 +1884,13 @@ continue; Address ParentVar = I->second; - setAddrOfLocalVar( - VD, recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP)); + Address Recovered = recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP); + setAddrOfLocalVar(VD, Recovered); + + if (isa(VD)) { + CXXThisValue = Builder.CreateLoad(Recovered, "this"); + CXXABIThisValue = CXXThisValue; + } } if (Finder.SEHCodeSlot.isValid()) { diff --git a/clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp b/clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp --- a/clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp +++ b/clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp @@ -39,13 +39,13 @@ int l1 = 13; __try { might_crash(); - } __except(basic_filter(l1)) { - // FIXME: Test capturing 'this' and 'm1'. + } __except(basic_filter(l1, m1)) { } } // CHECK-LABEL: define dso_local void @"?test_method@S@@QEAAXXZ"(%struct.S* {{[^,]*}} %this) -// CHECK: @llvm.localescape(i32* %[[l1_addr:[^, ]*]]) +// CHECK: @llvm.localescape(i32* %[[l1_addr:[^, ]*]], %struct.S** %[[this_addr:[^, ]*]]) +// CHECK: store %struct.S* %this, %struct.S** %[[this_addr]], align 8 // CHECK: store i32 13, i32* %[[l1_addr]], align 4 // CHECK: invoke void @might_crash() @@ -53,8 +53,46 @@ // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (%struct.S*)* @"?test_method@S@@QEAAXXZ" to i8*), i8* %frame_pointer) // CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"?test_method@S@@QEAAXXZ" to i8*), i8* %[[fp]], i32 0) // CHECK: %[[l1_ptr:[^ ]*]] = bitcast i8* %[[l1_i8]] to i32* +// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"?test_method@S@@QEAAXXZ" to i8*), i8* %[[fp]], i32 1) +// CHECK: %[[this_ptr:[^ ]*]] = bitcast i8* %[[this_i8]] to %struct.S** +// CHECK: %[[this:[^ ]*]] = load %struct.S*, %struct.S** %[[this_ptr]], align 8 +// CHECK: %[[m1_ptr:[^ ]*]] = getelementptr inbounds %struct.S, %struct.S* %[[this]], i32 0, i32 0 +// CHECK: %[[m1:[^ ]*]] = load i32, i32* %[[m1_ptr]] // CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ptr]] -// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]]) +// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]], i32 %[[m1]]) + + +struct V { + void test_virtual(int p1); + virtual void virt(int p1); +}; + +void V::test_virtual(int p1) { + __try { + might_crash(); + } __finally { + virt(p1); + } +} + +// CHECK-LABEL: define dso_local void @"?test_virtual@V@@QEAAXH@Z"(%struct.V* {{[^,]*}} %this, i32 %p1) +// CHECK: @llvm.localescape(%struct.V** %[[this_addr:[^, ]*]], i32* %[[p1_addr:[^, ]*]]) +// CHECK: store i32 %p1, i32* %[[p1_addr]], align 4 +// CHECK: store %struct.V* %this, %struct.V** %[[this_addr]], align 8 +// CHECK: invoke void @might_crash() + +// CHECK-LABEL: define internal void @"?fin$0@0@test_virtual@V@@"(i8 %abnormal_termination, i8* %frame_pointer) +// 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) +// CHECK: %[[this_ptr:[^ ]*]] = bitcast i8* %[[this_i8]] to %struct.V** +// CHECK: %[[this:[^ ]*]] = load %struct.V*, %struct.V** %[[this_ptr]], align 8 +// 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) +// CHECK: %[[p1_ptr:[^ ]*]] = bitcast i8* %[[p1_i8]] to i32* +// CHECK: %[[p1:[^ ]*]] = load i32, i32* %[[p1_ptr]] +// CHECK: %[[this_2:[^ ]*]] = bitcast %struct.V* %[[this]] to void (%struct.V*, i32)*** +// CHECK: %[[vtable:[^ ]*]] = load void (%struct.V*, i32)**, void (%struct.V*, i32)*** %[[this_2]], align 8 +// CHECK: %[[vfn:[^ ]*]] = getelementptr inbounds void (%struct.V*, i32)*, void (%struct.V*, i32)** %[[vtable]], i64 0 +// CHECK: %[[virt:[^ ]*]] = load void (%struct.V*, i32)*, void (%struct.V*, i32)** %[[vfn]], align 8 +// CHECK: call void %[[virt]](%struct.V* {{[^,]*}} %[[this]], i32 %[[p1]]) void test_lambda() { int l1 = 13; @@ -62,21 +100,28 @@ int l2 = 42; __try { might_crash(); - } __except(basic_filter(l2)) { - // FIXME: Test 'l1' when we can capture the lambda's 'this' decl. + } __except(basic_filter(l1, l2)) { } }; lambda(); } // CHECK-LABEL: define internal void @"??R@?0??test_lambda@@YAXXZ@QEBA@XZ"(%class.anon* {{[^,]*}} %this) -// CHECK: @llvm.localescape(i32* %[[l2_addr:[^, ]*]]) +// CHECK: @llvm.localescape(%class.anon** %[[this_addr:[^, ]*]], i32* %[[l2_addr:[^, ]*]]) +// CHECK: store %class.anon* %this, %class.anon** %[[this_addr]], align 8 // CHECK: store i32 42, i32* %[[l2_addr]], align 4 // CHECK: invoke void @might_crash() // CHECK-LABEL: define internal i32 @"?filt$0@0@?R@?0??test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer) // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (%class.anon*)* @"??R@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %frame_pointer) -// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 0) +// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 0) +// CHECK: %[[this_ptr:[^ ]*]] = bitcast i8* %[[this_i8]] to %class.anon** +// CHECK: %[[this:[^ ]*]] = load %class.anon*, %class.anon** %[[this_ptr]], align 8 +// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R@?0??test_lambda@@YAXXZ@QEBA@XZ" to i8*), i8* %[[fp]], i32 1) // CHECK: %[[l2_ptr:[^ ]*]] = bitcast i8* %[[l2_i8]] to i32* // CHECK: %[[l2:[^ ]*]] = load i32, i32* %[[l2_ptr]] -// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l2]]) +// CHECK: %[[l1_ref_ptr:[^ ]*]] = getelementptr inbounds %class.anon, %class.anon* %[[this]], i32 0, i32 0 +// CHECK: %[[l1_ref:[^ ]*]] = load i32*, i32** %[[l1_ref_ptr]] +// CHECK: %[[l1:[^ ]*]] = load i32, i32* %[[l1_ref]] +// CHECK: call i32 (i32, ...) @basic_filter(i32 %[[l1]], i32 %[[l2]]) +