]> granicus.if.org Git - clang/commitdiff
Collect SEH captures in a set instead of a vector to avoid
authorJohn McCall <rjmccall@apple.com>
Tue, 8 Sep 2015 21:15:22 +0000 (21:15 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 8 Sep 2015 21:15:22 +0000 (21:15 +0000)
doing redundant work if a variable is used multiple times.

Fixes PR24751.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247075 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGException.cpp
test/CodeGen/exceptions-seh.c

index 8de626e17413fc29a9cb24b9f8fa80f52cb21288..5549239a8f794a073f06ff5d10554a306a45c3de 100644 (file)
@@ -1433,7 +1433,7 @@ namespace {
 struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
   CodeGenFunction &ParentCGF;
   const VarDecl *ParentThis;
-  SmallVector<const VarDecl *, 4> Captures;
+  llvm::SmallSetVector<const VarDecl *, 4> Captures;
   Address SEHCodeSlot = Address::invalid();
   CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
       : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
@@ -1454,17 +1454,17 @@ struct CaptureFinder : ConstStmtVisitor<CaptureFinder> {
   void VisitDeclRefExpr(const DeclRefExpr *E) {
     // If this is already a capture, just make sure we capture 'this'.
     if (E->refersToEnclosingVariableOrCapture()) {
-      Captures.push_back(ParentThis);
+      Captures.insert(ParentThis);
       return;
     }
 
     const auto *D = dyn_cast<VarDecl>(E->getDecl());
     if (D && D->isLocalVarDeclOrParm() && D->hasLocalStorage())
-      Captures.push_back(D);
+      Captures.insert(D);
   }
 
   void VisitCXXThisExpr(const CXXThisExpr *E) {
-    Captures.push_back(ParentThis);
+    Captures.insert(ParentThis);
   }
 
   void VisitCallExpr(const CallExpr *E) {
index 9707a9a31bebc6ef3bb3687ec8b84286dd09caef..d56f8b30561e17aa7be94bee8d88f1cb5e047d39 100644 (file)
@@ -230,4 +230,34 @@ int except_return(void) {
 // CHECK: %[[r:[^ ]*]] = load i32, i32* %[[rv]]
 // CHECK: ret i32 %[[r]]
 
+
+// PR 24751: don't assert if a variable is used twice in a __finally block.
+// Also, make sure we don't do redundant work to capture/project it.
+void finally_capture_twice(int x) {
+  __try {
+  } __finally {
+    int y = x;
+    int z = x;
+  }
+}
+//  
+// CHECK-LABEL: define void @finally_capture_twice(
+// CHECK:         [[X:%.*]] = alloca i32, align 4
+// CHECK:         call void (...) @llvm.localescape(i32* [[X]])
+// CHECK-NEXT:    store i32 {{.*}}, i32* [[X]], align 4
+// CHECK-NEXT:    [[LOCAL:%.*]] = call i8* @llvm.localaddress()
+// CHECK-NEXT:    call void [[FINALLY:@.*]](i8{{ zeroext | }}0, i8* [[LOCAL]])
+// CHECK:       define internal void [[FINALLY]](
+// CHECK:         [[LOCAL:%.*]] = call i8* @llvm.localrecover(
+// CHECK:         [[X:%.*]] = bitcast i8* [[LOCAL]] to i32*
+// CHECK-NEXT:    [[Y:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[Z:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    store i8*
+// CHECK-NEXT:    store i8
+// CHECK-NEXT:    [[T0:%.*]] = load i32, i32* [[X]], align 4
+// CHECK-NEXT:    store i32 [[T0]], i32* [[Y]], align 4
+// CHECK-NEXT:    [[T0:%.*]] = load i32, i32* [[X]], align 4
+// CHECK-NEXT:    store i32 [[T0]], i32* [[Z]], align 4
+// CHECK-NEXT:    ret void
+
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }