[clang] 1b04bdc - [SEH] capture 'this'

Olivier Goffart via cfe-commits cfe-commits at lists.llvm.org
Mon Mar 1 02:59:12 PST 2021


Author: Olivier Goffart
Date: 2021-03-01T11:57:35+01:00
New Revision: 1b04bdc2f3ffaa7a0e1e3dbdc3a0cd08f0b9a4ce

URL: https://github.com/llvm/llvm-project/commit/1b04bdc2f3ffaa7a0e1e3dbdc3a0cd08f0b9a4ce
DIFF: https://github.com/llvm/llvm-project/commit/1b04bdc2f3ffaa7a0e1e3dbdc3a0cd08f0b9a4ce.diff

LOG: [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

Added: 
    

Modified: 
    clang/lib/CodeGen/CGException.cpp
    clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp
index 7a64963183bc..ce8b42a8c63f 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -1702,10 +1702,8 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
 
   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<VarDecl>(E->getDecl());
     if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())
@@ -1865,11 +1863,6 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
 
   // Create llvm.localrecover calls for all captures.
   for (const VarDecl *VD : Finder.Captures) {
-    if (isa<ImplicitParamDecl>(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 +1870,12 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
     assert((isa<ImplicitParamDecl>(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 +1883,14 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
       continue;
 
     Address ParentVar = I->second;
-    setAddrOfLocalVar(
-        VD, recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP));
+    Address Recovered =
+        recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);
+    setAddrOfLocalVar(VD, Recovered);
+
+    if (isa<ImplicitParamDecl>(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
index ac33dbff0b1c..f6cca8eda9d9 100644
--- a/clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh-filter-captures.cpp
@@ -39,13 +39,13 @@ void S::test_method() {
   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 at 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,45 @@ void S::test_method() {
 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (%struct.S*)* @"?test_method at S@@QEAAXXZ" to i8*), i8* %frame_pointer)
 // CHECK: %[[l1_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.S*)* @"?test_method at 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 at 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 at V@@QEAAXH at 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 at 0@test_virtual at V@@"(i8 %abnormal_termination, i8* %frame_pointer)
+// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%struct.V*, i32)* @"?test_virtual at V@@QEAAXH at 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 at V@@QEAAXH at 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 +99,27 @@ void test_lambda() {
     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<lambda_0>@?0??test_lambda@@YAXXZ at 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 at 0@?R<lambda_0>@?0??test_lambda@@YAXXZ@"(i8* %exception_pointers, i8* %frame_pointer)
 // CHECK: %[[fp:[^ ]*]] = call i8* @llvm.eh.recoverfp(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ at QEBA@XZ" to i8*), i8* %frame_pointer)
-// CHECK: %[[l2_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ at QEBA@XZ" to i8*), i8* %[[fp]], i32 0)
+// CHECK: %[[this_i8:[^ ]*]] = call i8* @llvm.localrecover(i8* bitcast (void (%class.anon*)* @"??R<lambda_0>@?0??test_lambda@@YAXXZ at 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<lambda_0>@?0??test_lambda@@YAXXZ at 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]])


        


More information about the cfe-commits mailing list