[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-02-05 Thread via cfe-commits

GkvJwa wrote:

> Oh, your code wasn't blowing up in clang because you weren't using /EHa, 
> which makes clang handle __try differently. Which makes it less likely to 
> blow up, but also doesn't really work properly (see #62606).

Yes, Chromium does not enable /eha by default. This allows it to compile.
If using /eha, Before this patch, the compiled code might produce unexpected 
results. In other words, a real error might not throw an exception.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-02-03 Thread via cfe-commits


@@ -4,6 +4,12 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \

GkvJwa wrote:

Okay, I'll add it today.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-02-03 Thread Mikael Holmen via cfe-commits


@@ -4,6 +4,12 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \

mikaelholmen wrote:

Hi @GkvJwa 

The new RUN lines try to write the output to files in the local directory, 
which may be write protected.
Can we redirect the output, or disable it completely if it's not interesting?

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-02-03 Thread via cfe-commits

https://github.com/GkvJwa closed 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-02-03 Thread via cfe-commits

GkvJwa wrote:

@rnk @efriedma-quic @MuellerMP hello, help confirm if there are any other 
issues. If not, I will merge it into the main branch this week. Then, handle 
another case.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-02-03 Thread via cfe-commits

GkvJwa wrote:

> > This case(new and delete object) I think we should probably fix the EH 
> > numbering algorithm, This does not conflict with This PR
> 
> I argued throughout this PR that "fixing this in EH numbering" is not optimal 
> since mixing SEH with C++ unwinding is generally not allowed in MS C++ and 
> only seems to be supported by Borland C++. In the latter case I do not know 
> how unwinding is generated (e.g. which personality is chosen).
> 
> What i noticed though: even if we mark the dtor as virtual for the delete 
> sample there is still a scope begin+end. That is also true if we delete the 
> delete call and just have the ctor present. Since this is legal in MS C++ I 
> guess one can argue that we should indeed respect c++ scope begin/end 
> intrinsics in the `calculateSEHStateForAsynchEH` numbering algo.

I checked the IR for this case.
```
invoke.cont2: ; preds = %invoke.cont1
  invoke void @llvm.seh.scope.begin()
  to label %invoke.cont3 unwind label %ehcleanup

invoke.cont3: ; preds = %invoke.cont2
  store volatile ptr %call, ptr %a, align 8
  %0 = load volatile ptr, ptr %a, align 8
  %isnull = icmp eq ptr %0, null
  br i1 %isnull, label %delete.end, label %delete.notnull

delete.notnull:   ; preds = %invoke.cont3
  invoke void @llvm.seh.scope.begin()
  to label %invoke.cont6 unwind label %ehcleanup10

invoke.cont6: ; preds = %delete.notnull
  invoke void @"??1A@@QEAA@XZ"(ptr noundef nonnull align 1 dereferenceable(1) 
%0) #9
  to label %invoke.cont7 unwind label %ehcleanup10

invoke.cont7: ; preds = %invoke.cont6
  invoke void @llvm.seh.try.end()
  to label %invoke.cont8 unwind label %ehcleanup10

invoke.cont8: ; preds = %invoke.cont7
  invoke void @"??3@YAXPEAX_K@Z"(ptr noundef %0, i64 noundef 1) #10
  to label %invoke.cont9 unwind label %ehcleanup14

invoke.cont9: ; preds = %invoke.cont8
  br label %delete.end

delete.end:   ; preds = %invoke.cont9, 
%invoke.cont3
  invoke void @llvm.seh.try.end()
  to label %invoke.cont13 unwind label %ehcleanup14

invoke.cont13:; preds = %delete.end
  %1 = call ptr @llvm.localaddress()
  call void @"?fin$0@0@f@@"(i8 noundef 0, ptr noundef %1)
  ret void
```

`delete.notnull` include `llvm.seh.scope.begin`, but `delete.end` 
not(`delete.notnull` also br `delete.end` too
This prevents `new` and `delete` from being compiled into the `__try` block 
simultaneously, unlike in MSVC.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-27 Thread via cfe-commits

GkvJwa wrote:

> > This case(new and delete object) I think we should probably fix the EH 
> > numbering algorithm, This does not conflict with This PR
> 
> I argued throughout this PR that "fixing this in EH numbering" is not optimal 
> since mixing SEH with C++ unwinding is generally not allowed in MS C++ and 
> only seems to be supported by Borland C++. In the latter case I do not know 
> how unwinding is generated (e.g. which personality is chosen).
> 
> What i noticed though: even if we mark the dtor as virtual for the delete 
> sample there is still a scope begin+end. That is also true if we delete the 
> delete call and just have the ctor present. Since this is legal in MS C++ I 
> guess one can argue that we should indeed respect c++ scope begin/end 
> intrinsics in the `calculateSEHStateForAsynchEH` numbering algo.

Yes, because using MSVC is effective. impl can be discussed further.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-26 Thread via cfe-commits

MuellerMP wrote:

> This case(new and delete object) I think we should probably fix the EH 
> numbering algorithm, This does not conflict with This PR

I argued throughout this PR that "fixing this in EH numbering" is not optimal 
since mixing SEH with C++ unwinding is generally not allowed in MS C++ and only 
seems to be supported by Borland C++. In the latter case I do not know how 
unwinding is generated (e.g. which personality is chosen).

What i noticed though: even if we mark the dtor as virtual for the delete 
sample there is still a scope begin+end.
That is also true if we delete the delete call and just have the ctor present.
Since this is legal in MS C++ I guess one can argue that we should indeed 
respect that in the numbering algo.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-22 Thread via cfe-commits

GkvJwa wrote:

> This is not related to the issue I'm trying to fix currently.
> 
> My first guess would be that there might be an unwinding pad that only gets 
> generated in clang and not in msvc.
> 
> Edit: I just looked at the original issue. So I think it would be valid to 
> reject this code if we don't use the deleting dtor right? Does the current 
> fix already reject this?

The current fix will not reject this case, creating objects using `new` and 
`delete` does not belong to DestructionKind.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-22 Thread via cfe-commits

MuellerMP wrote:

This is not related to the issue I'm trying to fix currently.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-22 Thread via cfe-commits


@@ -175,3 +181,26 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() {
+  __try {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}

GkvJwa wrote:

Review again

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-22 Thread via cfe-commits


@@ -2212,8 +2212,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const 
AutoVarEmission &emission) {
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
+// Check if we're in a SEH block and this is a C++ destructor
+if (dtorKind == QualType::DK_cxx_destructor)

GkvJwa wrote:

Review again

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-22 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 3be184c8b6d26d66f27e32d95a2da3a5ca962384 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 22 Jan 2026 16:59:50 +0800
Subject: [PATCH] Prevent functions has object unwinding when use seh on
 windows

---
 .../clang/Basic/DiagnosticCommonKinds.td  |  2 ++
 clang/lib/CodeGen/CGDecl.cpp  |  7 -
 clang/test/CodeGenCXX/exceptions-seh.cpp  | 29 +++
 3 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td 
b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 6e50e225a8cc1..8eadbf2ba9042 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -286,6 +286,8 @@ def err_seh___except_filter : Error<
   "%0 only allowed in __except filter expression">;
 def err_seh___finally_block : Error<
   "%0 only allowed in __finally block">;
+def err_seh_object_unwinding : Error<
+  "'__try' is not permitted in functions that require object unwinding">;
 
 // Sema && AST
 def note_invalid_subexpr_in_const_expr : Note<
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8b1cd83af2396..3d9df61d4dab3 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -2212,8 +2212,13 @@ void CodeGenFunction::EmitAutoVarCleanups(const 
AutoVarEmission &emission) {
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
+// Check if we're in a SEH block, prevent it
+if (currentFunctionUsesSEHTry())
+  getContext().getDiagnostics().Report(D.getLocation(),
+   diag::err_seh_object_unwinding);
 emitAutoVarTypeCleanup(emission, dtorKind);
+  }
 
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp 
b/clang/test/CodeGenCXX/exceptions-seh.cpp
index bb374dd1f5bd5..22665a0c8fcc3 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -4,6 +4,12 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR1
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR2
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR3
 
 extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
@@ -175,3 +181,26 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() {
+  __try {
+HasCleanup x; // expected-error{{'__try' is not permitted in functions 
that require object unwinding}}
+  } __except (1) {
+  }
+}
+#elif defined(ERR2)
+void seh_unwinding() {
+  __try {
+  } __except (1) {
+HasCleanup x; // expected-error{{'__try' is not permitted in functions 
that require object unwinding}}
+  }
+}
+#elif defined(ERR3)
+void seh_unwinding() {
+  HasCleanup x; // expected-error{{'__try' is not permitted in functions that 
require object unwinding}}
+  __try {
+  } __except (1) {
+  }
+}
+#endif

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-21 Thread via cfe-commits

GkvJwa wrote:

> I'm not sure this catches all the cases we need to catch; for example, 
> #109576 has a testcase with a new expression.

```
struct A {
  ~A();
};

void f() {
  __try {
A* a = new A;
delete a;
  } __finally {
  }
}
```

This is valid in MSVC, and I think this might be the issue that @MuellerMP is 
fixing.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-21 Thread via cfe-commits

GkvJwa wrote:

> Fix seems reasonable to me. The "out-of-try/except-block" issue could be a 
> side effect of a missing stop gate for the try (I'm trying to fix an issue 
> related to that in a different PR at least). The final decision belongs to 
> the assigned reviewers though since I'm just a contributer.

Thanks

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-20 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From f16a7e15a2e54d2bb0090a06d99181176abb65e5 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Tue, 20 Jan 2026 22:50:18 +0800
Subject: [PATCH] Test

---
 clang/lib/CodeGen/CGDecl.cpp |  8 ++-
 clang/test/CodeGenCXX/exceptions-seh.cpp | 29 
 2 files changed, 36 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8b1cd83af2396..182570d9586a7 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -2212,8 +2212,14 @@ void CodeGenFunction::EmitAutoVarCleanups(const 
AutoVarEmission &emission) {
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
+// Check if we're in a SEH block and this is a C++ destructor
+if (dtorKind == QualType::DK_cxx_destructor)
+  if (currentFunctionUsesSEHTry())
+getContext().getDiagnostics().Report(D.getLocation(),
+ diag::err_seh_expected_handler);
 emitAutoVarTypeCleanup(emission, dtorKind);
+  }
 
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp 
b/clang/test/CodeGenCXX/exceptions-seh.cpp
index bb374dd1f5bd5..6a48e8384bb34 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -4,6 +4,12 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR1
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR2
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR3
 
 extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
@@ -175,3 +181,26 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() {
+  __try {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  } __except (1) {
+  }
+}
+#elif defined(ERR2)
+void seh_unwinding() {
+  __try {
+  } __except (1) {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  }
+}
+#elif defined(ERR3)
+void seh_unwinding() {
+  HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  __try {
+  } __except (1) {
+  }
+}
+#endif

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2026-01-12 Thread via cfe-commits

GkvJwa wrote:

> Hey, just wanted to add references to the previous discussions about the 
> issue: Here is an implementation of the sema check: 
> https://github.com/llvm/llvm-project/pull/151836/files Here is another bug 
> report about the issue: #82917

Got it. It seems it doesn't work outside of the block either.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-31 Thread via cfe-commits

m4arhz wrote:

Hey, just wanted to add references to the previous discussions about the issue:
Here is an implementation of the sema check: 
https://github.com/llvm/llvm-project/pull/151836/files
Here is another bug report about the issue: 
https://github.com/llvm/llvm-project/issues/82917

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-28 Thread via cfe-commits

GkvJwa wrote:

I think this might be a good way to solve this problem. 

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-28 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 1adba34a4702c5372c835dac9972829fad2662e4 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Mon, 29 Dec 2025 00:20:05 +0800
Subject: [PATCH] Test

---
 clang/lib/CodeGen/CGDecl.cpp | 15 ++-
 clang/test/CodeGenCXX/exceptions-seh.cpp | 20 
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8b1cd83af2396..21b6dc9444943 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -2212,8 +2212,21 @@ void CodeGenFunction::EmitAutoVarCleanups(const 
AutoVarEmission &emission) {
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
+// Check if we're in a SEH block and this is a C++ destructor
+if (dtorKind == QualType::DK_cxx_destructor) {
+  if (isSEHTryScope()) {
+// We're in a __try block
+getContext().getDiagnostics().Report(D.getLocation(),
+ diag::err_seh_expected_handler);
+  } else if (!SEHCodeSlotStack.empty()) {
+// We're in an __except block
+getContext().getDiagnostics().Report(D.getLocation(),
+ diag::err_seh_expected_handler);
+  }
+}
 emitAutoVarTypeCleanup(emission, dtorKind);
+  }
 
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp 
b/clang/test/CodeGenCXX/exceptions-seh.cpp
index bb374dd1f5bd5..87adde5ff1baa 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -4,6 +4,10 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR1
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR2
 
 extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
@@ -175,3 +179,19 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() {
+  __try {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  } __except (1) {
+  }
+}
+#elif defined(ERR2)
+void seh_unwinding() {
+  __try {
+  } __except (1) {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  }
+}
+#endif

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-28 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 98fa6cd36dcfaa61f957201943ee661c07870833 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Sun, 28 Dec 2025 23:53:25 +0800
Subject: [PATCH] Test

---
 clang/lib/CodeGen/CGDecl.cpp | 15 ++-
 clang/lib/CodeGen/CGException.cpp|  2 ++
 clang/lib/CodeGen/CodeGenFunction.h  |  3 +++
 clang/test/CodeGenCXX/exceptions-seh.cpp | 20 
 4 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8b1cd83af2396..1216403eeba1a 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -2212,8 +2212,21 @@ void CodeGenFunction::EmitAutoVarCleanups(const 
AutoVarEmission &emission) {
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
+// Check if we're in a SEH block and this is a C++ destructor
+if (dtorKind == QualType::DK_cxx_destructor) {
+  if (isSEHTryScope()) {
+// We're in a __try block
+getContext().getDiagnostics().Report(D.getLocation(),
+ diag::err_seh_expected_handler);
+  } else if (InSEHExceptBlock) {
+// We're in an __except block
+getContext().getDiagnostics().Report(D.getLocation(),
+ diag::err_seh_expected_handler);
+  }
+}
 emitAutoVarTypeCleanup(emission, dtorKind);
+  }
 
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
diff --git a/clang/lib/CodeGen/CGException.cpp 
b/clang/lib/CodeGen/CGException.cpp
index e9d20672ce185..bd41343d345bf 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -2270,7 +2270,9 @@ void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) 
{
   }
 
   // Emit the __except body.
+  InSEHExceptBlock = true;
   EmitStmt(Except->getBlock());
+  InSEHExceptBlock = false;
 
   // End the lifetime of the exception code.
   SEHCodeSlotStack.pop_back();
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 855e43631f436..4ea6e9de04dae 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -589,6 +589,9 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   GlobalDecl CurSEHParent;
 
+  // Track if we're currently emitting __except block
+  bool InSEHExceptBlock = false;
+
   /// True if the current function is an outlined SEH helper. This can be a
   /// finally block or filter expression.
   bool IsOutlinedSEHHelper = false;
diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp 
b/clang/test/CodeGenCXX/exceptions-seh.cpp
index bb374dd1f5bd5..87adde5ff1baa 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -4,6 +4,10 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR1
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR2
 
 extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
@@ -175,3 +179,19 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() {
+  __try {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  } __except (1) {
+  }
+}
+#elif defined(ERR2)
+void seh_unwinding() {
+  __try {
+  } __except (1) {
+HasCleanup x; // expected-error{{expected '__except' or '__finally' block}}
+  }
+}
+#endif

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-25 Thread via cfe-commits

GkvJwa wrote:

> Ahh okay there is even more issues hidden here sadly: `__try`+`__finally` 
> (``) uses `NormalAndEHCleanup` aswell and thus emits 
> `seh.scope.begin` even though the state numbering algo ignores it. This makes 
> fixing this very tricky. I might take a further look as well once christmas 
> holidays have passed.

Yes, it's indeed difficult to solve this problem without processing through 
`Stmt`. Many concepts (such as determining whether a destructor exists within a 
`__try` or `__except` block) do not exist in `CodeGenFunction`.

Let's go on vacation first. Have a great holiday!

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-25 Thread via cfe-commits

MuellerMP wrote:

Ahh okay there is even more issues hidden here sadly: `__try`+`__finally` 
(``) uses `NormalAndEHCleanup` aswell and thus emits 
`seh.scope.begin` even though the state numbering algo ignores it.
This makes fixing this very tricky. I might take a further look as well once 
christmas holidays have passed.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-24 Thread via cfe-commits

github-actions[bot] wrote:


# :window: Windows x64 Test Results

* 51645 tests passed
* 889 tests skipped
* 1 test failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.CodeGen/windows-seh-EHa-TryInFinally.cpp

```
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
c:\_work\llvm-project\llvm-project\build\bin\clang.exe -cc1 -internal-isystem 
C:\_work\llvm-project\llvm-project\build\lib\clang\22\include -nostdsysteminc 
-triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions 
-fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm 
C:\_work\llvm-project\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp
 -o - | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe 
C:\_work\llvm-project\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\clang.exe' 
-cc1 -internal-isystem 
'C:\_work\llvm-project\llvm-project\build\lib\clang\22\include' -nostdsysteminc 
-triple x86_64-windows -fasync-exceptions -fcxx-exceptions -fexceptions 
-fms-extensions -x c++ -Wno-implicit-function-declaration -emit-llvm 
'C:\_work\llvm-project\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp'
 -o -
# .---command stderr
# | 
C:\_work\llvm-project\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp:19:5:
 error: expected '__except' or '__finally' block
# |19 | int main() {
# |   | ^
# | 1 error generated.
# `-
# error: command failed with exit status: 1
# executed command: 
'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 
'C:\_work\llvm-project\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp'
# .---command stderr
# | FileCheck error: '' is empty.
# | FileCheck command line:  
c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe 
C:\_work\llvm-project\llvm-project\clang\test\CodeGen\windows-seh-EHa-TryInFinally.cpp
# `-
# error: command failed with exit status: 2

--

```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-24 Thread via cfe-commits

github-actions[bot] wrote:


# :penguin: Linux x64 Test Results

* 85227 tests passed
* 1191 tests skipped
* 1 test failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.CodeGen/windows-seh-EHa-TryInFinally.cpp

```
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 
-internal-isystem 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/22/include
 -nostdsysteminc -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration 
-emit-llvm 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
 -o - | 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
# executed command: 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 
-internal-isystem 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/22/include
 -nostdsysteminc -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration 
-emit-llvm 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
 -o -
# .---command stderr
# | 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp:19:5:
 error: expected '__except' or '__finally' block
# |19 | int main() {
# |   | ^
# | 1 error generated.
# `-
# error: command failed with exit status: 1
# executed command: 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
# .---command stderr
# | FileCheck error: '' is empty.
# | FileCheck command line:  
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
# `-
# error: command failed with exit status: 2

--

```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-24 Thread via cfe-commits

GkvJwa wrote:

Hey, I continued debugging and found that the purpose of `getInvokeDest` is 
actually to determine whether an object's destructor exists. The problem here 
is that its granularity is not fine enough; it's not at the function block 
level, which prevents it from handling destructors within `__try/__except` 
blocks.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-24 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From b9e4660051b70d266a6542586959aa4caf863c38 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 24 Dec 2025 23:32:24 +0800
Subject: [PATCH] Test

---
 clang/lib/CodeGen/CGCleanup.cpp  |  6 +-
 clang/test/CodeGenCXX/exceptions-seh.cpp | 20 
 2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 28ac9bf396356..2afd16e8d5708 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -191,8 +191,12 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t 
Size) {
   // consistent with MSVC's behavior, except in the presence of -EHa.
   // Check getInvokeDest() to generate llvm.seh.scope.begin() as needed.
   if (CGF->getLangOpts().EHAsynch && IsEHCleanup && !IsLifetimeMarker &&
-  CGF->getTarget().getCXXABI().isMicrosoft() && CGF->getInvokeDest())
+  CGF->getTarget().getCXXABI().isMicrosoft() && CGF->getInvokeDest()) {
+if (IsNormalCleanup && !CGF->SEHCodeSlotStack.empty())
+  CGF->CGM.getDiags().Report(CGF->CurFuncDecl->getLocation(),
+ diag::err_seh_expected_handler);
 CGF->EmitSehCppScopeBegin();
+  }
 
   return Scope->getCleanupBuffer();
 }
diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp 
b/clang/test/CodeGenCXX/exceptions-seh.cpp
index bb374dd1f5bd5..2f5c43b7cbd58 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -4,6 +4,10 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR1
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -fms-extensions -x c++ -emit-llvm -verify %s -DERR2
 
 extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
@@ -175,3 +179,19 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() { // expected-error{{expected '__except' or '__finally' 
block}}
+  __try {
+HasCleanup x;
+  } __except (1) {
+  }
+}
+#elif defined(ERR2)
+void seh_unwinding() { // expected-error{{expected '__except' or '__finally' 
block}}
+  __try {
+  } __except (1) {
+HasCleanup x;
+  }
+}
+#endif

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-22 Thread via cfe-commits

GkvJwa wrote:

> @GkvJwa I don't understand the added message in your last comment. 
> [Previously](https://github.com/llvm/llvm-project/pull/172287#discussion_r2635384617)
>  you already identified the call stack which tells us how pushCleanup is 
> called. `NormalAndEHCleanup` does really mean it is a `NormalCleanup` + 
> `EHCleanup` so yes the code is executed -> thats really how the problematic 
> `seh.scope.begin` gets emitted for your case which causes the issue: 
> https://godbolt.org/z/hKW6vroeY .

What I'm trying to say is that with SEH enabled, `EmitCXXTemporary` in the 
`__try/__except` block should not actually be called.

`EmitCXXTemporary` executes `pushDestroy` to pass `NormalAndEHCleanup`
```
void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
   QualType TempType,
   Address Ptr) {
  pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
  /*useEHCleanup*/ true);
}
```

However, if we consider handling this within `pushCleanup`, Could it be 
misjudged as a normal use of `(pushCleanup + NormalAndEHCleanup)`?

This led me to wonder before if it was possible to make a judgment directly in 
this way.
```
void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
  ...
  if (CGF->getLangOpts().EHAsynch && IsEHCleanup && !IsLifetimeMarker &&
  CGF->getTarget().getCXXABI().isMicrosoft() && CGF->getInvokeDest()) {
  if (IsNormalCleanup) {
CGF->CGM.getDiags().Report(CGF->CurFuncDecl->getLocation(),
   diag::err_seh_expected_handler);
  }
}
CGF->EmitSehCppScopeBegin();
  }
```

I may communicate via code in the future (you can do that too), as there might 
be some misunderstandings in the text.


https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-22 Thread via cfe-commits

MuellerMP wrote:

@GkvJwa I don't understand the added message in your last comment.
[Previously](https://github.com/llvm/llvm-project/pull/172287#discussion_r2635384617)
 you already identified the call stack which tells us how pushCleanup is 
called. `NormalAndEHCleanup` does really mean it is a `NormalCleanup` + 
`EHCleanup` so yes the code is executed -> thats really how the problematic 
`seh.scope.begin` gets emitted for your case which causes the issue: 
https://godbolt.org/z/hKW6vroeY .

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-22 Thread via cfe-commits

GkvJwa wrote:

> > I think this flew under the radar when this was all getting implemented 
> > because we didn't handle async exceptions, so designed the problem away by 
> > just turning off EH cleanups if SEH try was used in a function body. I 
> > suppose -EHa undoes that logic, bringing this problem back to life.
> > Personally, I don't like the design proposed here of adding a standalone 
> > recursive walk of the AST and attempting to pattern match things that might 
> > not compile. If the asynch EH numbering algorithm has bugs, I think we'd be 
> > better off improving the backend diagnostic to try to make it more 
> > actionable to users with LLVM IR debug info. We can leverage the internal / 
> > user fatal error distinction and some source locations to emit a more 
> > readable error diagnostic and that will help in all cases, instead of 
> > having this pattern match that creates additional maintenance and that we 
> > can't guarantee fixes all holes in the asynch EH numbering scheme.
> 
> This reads similar to what i tried to suggest here: [#172287 
> (comment)](https://github.com/llvm/llvm-project/pull/172287#discussion_r2634654818)
> 
> In this case we just handle the case for emitting a `seh.scope.begin`, which 
> is exactly what we do not handle in the SEH state numbering (only in the CXX 
> state numbering).

like this?
```
  if (CGF->getLangOpts().EHAsynch && IsEHCleanup && !IsLifetimeMarker &&
  CGF->getTarget().getCXXABI().isMicrosoft() && CGF->getInvokeDest()) {
if (const auto *FD = dyn_cast(CGF->CurFuncDecl)) {
  if (FD->usesSEHTry()) {
CGF->CGM.getDiags().Report(CGF->CurFuncDecl->getLocation(),
   diag::err_seh_expected_handler);
  }
}
CGF->EmitSehCppScopeBegin();
  }
```

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-22 Thread via cfe-commits

MuellerMP wrote:

> I think this flew under the radar when this was all getting implemented 
> because we didn't handle async exceptions, so designed the problem away by 
> just turning off EH cleanups if SEH try was used in a function body. I 
> suppose -EHa undoes that logic, bringing this problem back to life.
> 
> Personally, I don't like the design proposed here of adding a standalone 
> recursive walk of the AST and attempting to pattern match things that might 
> not compile. If the asynch EH numbering algorithm has bugs, I think we'd be 
> better off improving the backend diagnostic to try to make it more actionable 
> to users with LLVM IR debug info. We can leverage the internal / user fatal 
> error distinction and some source locations to emit a more readable error 
> diagnostic and that will help in all cases, instead of having this pattern 
> match that creates additional maintenance and that we can't guarantee fixes 
> all holes in the asynch EH numbering scheme.

This reads similar to what i tried to suggest here: 
https://github.com/llvm/llvm-project/pull/172287#discussion_r2634654818

In this case we just handle the case for emitting a `seh.scope.begin`, which is 
exactly what we do not handle in the SEH state numbering (only in the CXX state 
numbering).

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-22 Thread via cfe-commits

GkvJwa wrote:

> I think this flew under the radar when this was all getting implemented 
> because we didn't handle async exceptions, so designed the problem away by 
> just turning off EH cleanups if SEH try was used in a function body. I 
> suppose -EHa undoes that logic, bringing this problem back to life.
> 
> Personally, I don't like the design proposed here of adding a standalone 
> recursive walk of the AST and attempting to pattern match things that might 
> not compile. If the asynch EH numbering algorithm has bugs, I think we'd be 
> better off improving the backend diagnostic to try to make it more actionable 
> to users with LLVM IR debug info. We can leverage the internal / user fatal 
> error distinction and some source locations to emit a more readable error 
> diagnostic and that will help in all cases, instead of having this pattern 
> match that creates additional maintenance and that we can't guarantee fixes 
> all holes in the asynch EH numbering scheme.

Yes, skipping it using the first instruction is indeed incorrect.(BB.isEHPad())
https://github.com/llvm/llvm-project/blob/0952ccc712ffc97943fbd0fc3c38a53e7aa875ac/llvm/lib/CodeGen/WinEHPrepare.cpp#L592-L608

I will try to make it, can also comment if anyone has an idea

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread Reid Kleckner via cfe-commits

rnk wrote:

I think this flew under the radar when this was all getting implemented because 
we didn't handle async exceptions, so designed the problem away by just turning 
off EH cleanups if SEH try was used in a function body. I suppose -EHa undoes 
that logic, bringing this problem back to life.

Personally, I don't like the design proposed here of adding a standalone 
recursive walk of the AST and attempting to pattern match things that might not 
compile. If the asynch EH numbering algorithm has bugs, I think we'd be better 
off improving the backend diagnostic to try to make it more actionable to users 
with LLVM IR debug info. We can leverage the internal / user fatal error 
distinction and some source locations to emit a more readable error diagnostic 
and that will help in all cases, instead of having this pattern match that 
creates additional maintenance and that we can't guarantee fixes all holes in 
the asynch EH numbering scheme.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From e1a11aa30ccf63162de6f7d9507460db9614362b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/6] Use sema

---
 clang/lib/Sema/SemaStmt.cpp   | 61 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 42 ++
 2 files changed, 103 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..a32d5c37b4605 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,55 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(const Stmt *S) {
+  if (!S)
+return nullptr;
+
+  llvm::SmallVector Worklist;
+  Worklist.push_back(S);
+
+  while (!Worklist.empty()) {
+const Stmt *Cur = Worklist.pop_back_val();
+if (!Cur)
+  continue;
+
+if (isa(Cur))
+  return nullptr;
+
+if (isa(Cur) || isa(Cur) ||
+isa(Cur)) {
+  return Cur;
+}
+
+if (isa(Cur) || isa(Cur)) {
+  return Cur;
+}
+
+if (const auto *DS = dyn_cast(Cur)) {
+  for (const Decl *D : DS->decls()) {
+if (const auto *VD = dyn_cast(D)) {
+  QualType QT = VD->getType();
+  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) {
+if (const CXXDestructorDecl *DD = RD->getDestructor()) {
+  if (!DD->isTrivial())
+return DS;
+}
+  }
+}
+  }
+}
+
+for (const Stmt *Child : Cur->children())
+  if (Child)
+Worklist.push_back(Child);
+  }
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4531,6 +4580,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   ? "'try'"
   : "'@try'");
 }
+if (const Stmt *Offending = findNonTrivialObject(TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
   }
 
   FSI->setHasSEHTry(TryLoc);
@@ -4562,6 +4615,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..bdc369ff767da 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,45 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+CheckError::Check("Caught a C-based exception."); // 
expected-error{{cannot use SEH '__try' in blocks}}
+  }
+  return e;
+}
+
+// has throw should work
+int foo__except_with_throw(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+throw(CheckError::Check("Caught a C-based exception."));
+  }
+  return e;
+}

>From 86db2c253868a1fb867497c88ee06a2d938696c1 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Sun, 21 Dec 2025 16:24:55 +0800
Subject: [PATCH 2/6] Revert "Use sema"

This reverts commit e1a11aa30ccf63162de6f7d9507460db9614362b.
---
 clang/lib/Sema/SemaStmt.cpp   | 61 ---
 clang/test/SemaCXX/exceptions-seh.cpp | 42 --
 2 files changed, 103 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index a32d5c37b4605..1b1643250d05e 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,55 +4515,6 @@ void Sema::DiagnoseExceptionUs

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

GkvJwa wrote:

hello, The description above also cannot handle some cases

1. I still plan to use a recursive function for the check(We can make further 
improvements later.)
There is similar processing within the coroutine(StmtCanThrow):
https://github.com/llvm/llvm-project/blob/0952ccc712ffc97943fbd0fc3c38a53e7aa875ac/clang/lib/CodeGen/CGCoroutine.cpp#L144-L179
2. The check has been moved inside the EnterSEHTryStmt.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

github-actions[bot] wrote:


# :window: Windows x64 Test Results

* 51620 tests passed
* 888 tests skipped
* 1 test failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.CodeGenCXX/exceptions-seh-filter-uwtable.cpp

```
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
c:\_work\llvm-project\llvm-project\build\bin\clang.exe -cc1 -internal-isystem 
C:\_work\llvm-project\llvm-project\build\lib\clang\22\include -nostdsysteminc 
"-triple" "arm64-windows" "-funwind-tables=2" "-fms-compatibility" -emit-llvm 
-O1 -disable-llvm-passes 
C:\_work\llvm-project\llvm-project\clang\test\CodeGenCXX\exceptions-seh-filter-uwtable.cpp
 -o - | c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe 
C:\_work\llvm-project\llvm-project\clang\test\CodeGenCXX\exceptions-seh-filter-uwtable.cpp
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\clang.exe' 
-cc1 -internal-isystem 
'C:\_work\llvm-project\llvm-project\build\lib\clang\22\include' -nostdsysteminc 
-triple arm64-windows -funwind-tables=2 -fms-compatibility -emit-llvm -O1 
-disable-llvm-passes 
'C:\_work\llvm-project\llvm-project\clang\test\CodeGenCXX\exceptions-seh-filter-uwtable.cpp'
 -o -
# .---command stderr
# | :35:6: error: cannot use SEH '__try' in blocks, captured regions, or Obj-C 
method decls
# |35 | void at() {
# |   |  ^
# | 1 error generated.
# `-
# error: command failed with exit status: 1
# executed command: 
'c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe' 
'C:\_work\llvm-project\llvm-project\clang\test\CodeGenCXX\exceptions-seh-filter-uwtable.cpp'
# .---command stderr
# | FileCheck error: '' is empty.
# | FileCheck command line:  
c:\_work\llvm-project\llvm-project\build\bin\filecheck.exe 
C:\_work\llvm-project\llvm-project\clang\test\CodeGenCXX\exceptions-seh-filter-uwtable.cpp
# `-
# error: command failed with exit status: 2

--

```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

github-actions[bot] wrote:


# :penguin: Linux x64 Test Results

* 85200 tests passed
* 1191 tests skipped
* 1 test failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.CodeGenCXX/exceptions-seh-filter-uwtable.cpp

```
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 
-internal-isystem 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/22/include
 -nostdsysteminc "-triple" "arm64-windows" "-funwind-tables=2" 
"-fms-compatibility" -emit-llvm -O1 -disable-llvm-passes 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGenCXX/exceptions-seh-filter-uwtable.cpp
 -o - | 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGenCXX/exceptions-seh-filter-uwtable.cpp
# executed command: 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 
-internal-isystem 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/22/include
 -nostdsysteminc -triple arm64-windows -funwind-tables=2 -fms-compatibility 
-emit-llvm -O1 -disable-llvm-passes 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGenCXX/exceptions-seh-filter-uwtable.cpp
 -o -
# .---command stderr
# | :35:6: error: cannot use SEH '__try' in blocks, captured regions, or Obj-C 
method decls
# |35 | void at() {
# |   |  ^
# | 1 error generated.
# `-
# error: command failed with exit status: 1
# executed command: 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGenCXX/exceptions-seh-filter-uwtable.cpp
# .---command stderr
# | FileCheck error: '' is empty.
# | FileCheck command line:  
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/FileCheck 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/CodeGenCXX/exceptions-seh-filter-uwtable.cpp
# `-
# error: command failed with exit status: 2

--

```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From e1a11aa30ccf63162de6f7d9507460db9614362b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/5] Use sema

---
 clang/lib/Sema/SemaStmt.cpp   | 61 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 42 ++
 2 files changed, 103 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..a32d5c37b4605 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,55 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(const Stmt *S) {
+  if (!S)
+return nullptr;
+
+  llvm::SmallVector Worklist;
+  Worklist.push_back(S);
+
+  while (!Worklist.empty()) {
+const Stmt *Cur = Worklist.pop_back_val();
+if (!Cur)
+  continue;
+
+if (isa(Cur))
+  return nullptr;
+
+if (isa(Cur) || isa(Cur) ||
+isa(Cur)) {
+  return Cur;
+}
+
+if (isa(Cur) || isa(Cur)) {
+  return Cur;
+}
+
+if (const auto *DS = dyn_cast(Cur)) {
+  for (const Decl *D : DS->decls()) {
+if (const auto *VD = dyn_cast(D)) {
+  QualType QT = VD->getType();
+  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) {
+if (const CXXDestructorDecl *DD = RD->getDestructor()) {
+  if (!DD->isTrivial())
+return DS;
+}
+  }
+}
+  }
+}
+
+for (const Stmt *Child : Cur->children())
+  if (Child)
+Worklist.push_back(Child);
+  }
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4531,6 +4580,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   ? "'try'"
   : "'@try'");
 }
+if (const Stmt *Offending = findNonTrivialObject(TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
   }
 
   FSI->setHasSEHTry(TryLoc);
@@ -4562,6 +4615,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..bdc369ff767da 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,45 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+CheckError::Check("Caught a C-based exception."); // 
expected-error{{cannot use SEH '__try' in blocks}}
+  }
+  return e;
+}
+
+// has throw should work
+int foo__except_with_throw(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+throw(CheckError::Check("Caught a C-based exception."));
+  }
+  return e;
+}

>From 86db2c253868a1fb867497c88ee06a2d938696c1 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Sun, 21 Dec 2025 16:24:55 +0800
Subject: [PATCH 2/5] Revert "Use sema"

This reverts commit e1a11aa30ccf63162de6f7d9507460db9614362b.
---
 clang/lib/Sema/SemaStmt.cpp   | 61 ---
 clang/test/SemaCXX/exceptions-seh.cpp | 42 --
 2 files changed, 103 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index a32d5c37b4605..1b1643250d05e 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,55 +4515,6 @@ void Sema::DiagnoseExceptionUs

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From e1a11aa30ccf63162de6f7d9507460db9614362b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/4] Use sema

---
 clang/lib/Sema/SemaStmt.cpp   | 61 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 42 ++
 2 files changed, 103 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..a32d5c37b4605 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,55 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(const Stmt *S) {
+  if (!S)
+return nullptr;
+
+  llvm::SmallVector Worklist;
+  Worklist.push_back(S);
+
+  while (!Worklist.empty()) {
+const Stmt *Cur = Worklist.pop_back_val();
+if (!Cur)
+  continue;
+
+if (isa(Cur))
+  return nullptr;
+
+if (isa(Cur) || isa(Cur) ||
+isa(Cur)) {
+  return Cur;
+}
+
+if (isa(Cur) || isa(Cur)) {
+  return Cur;
+}
+
+if (const auto *DS = dyn_cast(Cur)) {
+  for (const Decl *D : DS->decls()) {
+if (const auto *VD = dyn_cast(D)) {
+  QualType QT = VD->getType();
+  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) {
+if (const CXXDestructorDecl *DD = RD->getDestructor()) {
+  if (!DD->isTrivial())
+return DS;
+}
+  }
+}
+  }
+}
+
+for (const Stmt *Child : Cur->children())
+  if (Child)
+Worklist.push_back(Child);
+  }
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4531,6 +4580,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   ? "'try'"
   : "'@try'");
 }
+if (const Stmt *Offending = findNonTrivialObject(TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
   }
 
   FSI->setHasSEHTry(TryLoc);
@@ -4562,6 +4615,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..bdc369ff767da 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,45 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+CheckError::Check("Caught a C-based exception."); // 
expected-error{{cannot use SEH '__try' in blocks}}
+  }
+  return e;
+}
+
+// has throw should work
+int foo__except_with_throw(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+throw(CheckError::Check("Caught a C-based exception."));
+  }
+  return e;
+}

>From 86db2c253868a1fb867497c88ee06a2d938696c1 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Sun, 21 Dec 2025 16:24:55 +0800
Subject: [PATCH 2/4] Revert "Use sema"

This reverts commit e1a11aa30ccf63162de6f7d9507460db9614362b.
---
 clang/lib/Sema/SemaStmt.cpp   | 61 ---
 clang/test/SemaCXX/exceptions-seh.cpp | 42 --
 2 files changed, 103 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index a32d5c37b4605..1b1643250d05e 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,55 +4515,6 @@ void Sema::DiagnoseExceptionUs

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-codegen

Author: None (GkvJwa)


Changes

Consider the following code:
```
class CheckError {
 public:
  static CheckError Check();

  ~CheckError();
};

void Foo(const int* p) {
  int d = 0;
  __try {
d = *p;
  } __except (EXCEPTION_EXECUTE_HANDLER) {
::CheckError::Check();
  }
}

```

The following error will occur in mscv.
```
error C2712: Cannot use __try in functions that require object unwinding
```

However, using LLVM /EHa will cause it to crash.
```
llvm::SmallVectorTemplateCommon::operator[](unsigned
 __int64 idx) Line 295  C++
llvm::calculateSEHStateForAsynchEH(const llvm::BasicBlock * BB, int State, 
llvm::WinEHFuncInfo & EHInfo) Line 346   C++
llvm::calculateSEHStateNumbers(const llvm::Function * Fn, llvm::WinEHFuncInfo 
& FuncInfo) Line 612  C++
llvm::FunctionLoweringInfo::set(const llvm::Function & fn, 
llvm::MachineFunction & mf, llvm::SelectionDAG * DAG) Line 114   C++
llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction & mf) 
Line 588   C++
```

This patch is compatible with the crash(Unexpected state == -1)

---
Full diff: https://github.com/llvm/llvm-project/pull/172287.diff


2 Files Affected:

- (modified) clang/lib/CodeGen/CGException.cpp (+24) 
- (modified) clang/test/CodeGenCXX/exceptions-seh.cpp (+20) 


``diff
diff --git a/clang/lib/CodeGen/CGException.cpp 
b/clang/lib/CodeGen/CGException.cpp
index e9d20672ce185..3fc87e0e2456b 100644
--- a/clang/lib/CodeGen/CGException.cpp
+++ b/clang/lib/CodeGen/CGException.cpp
@@ -2170,6 +2170,26 @@ void CodeGenFunction::pushSEHCleanup(CleanupKind Kind,
   EHStack.pushCleanup(Kind, FinallyFunc);
 }
 
+static bool StmtCanNotSEH(const Stmt *S) {
+  if (!S)
+return false;
+
+  if (isa(S))
+return false;
+
+  if (isa(S))
+return true;
+
+  if (isa(S))
+return true;
+
+  for (const auto *child : S->children())
+if (StmtCanNotSEH(child))
+  return true;
+
+  return false;
+}
+
 void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
   CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
   HelperCGF.ParentCGF = this;
@@ -2186,6 +2206,10 @@ void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt 
&S) {
   // Otherwise, we must have an __except block.
   const SEHExceptStmt *Except = S.getExceptHandler();
   assert(Except);
+  if (!CGM.getLangOpts().Borland &&
+  (StmtCanNotSEH(&S) || StmtCanNotSEH(Except)))
+CGM.getDiags().Report(CurFuncDecl->getLocation(),
+  diag::err_seh_try_outside_functions);
   EHCatchScope *CatchScope = EHStack.pushCatch(1);
   SEHCodeSlotStack.push_back(
   CreateMemTemp(getContext().IntTy, "__exception_code"));
diff --git a/clang/test/CodeGenCXX/exceptions-seh.cpp 
b/clang/test/CodeGenCXX/exceptions-seh.cpp
index bb374dd1f5bd5..39c39b179983d 100644
--- a/clang/test/CodeGenCXX/exceptions-seh.cpp
+++ b/clang/test/CodeGenCXX/exceptions-seh.cpp
@@ -4,6 +4,10 @@
 // RUN: %clang_cc1 -std=c++11 -fblocks -fms-extensions %s 
-triple=x86_64-windows-msvc -emit-llvm \
 // RUN: -o - -mconstructor-aliases -O1 -disable-llvm-passes | \
 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=NOCXX
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -x c++ -emit-llvm -verify %s -DERR1
+// RUN: %clang_cc1 -triple x86_64-windows -fasync-exceptions -fcxx-exceptions 
-fexceptions \
+// RUN: -x c++ -emit-llvm -verify %s -DERR2
 
 extern "C" unsigned long _exception_code();
 extern "C" void might_throw();
@@ -175,3 +179,19 @@ void use_inline() {
 // CHECK: attributes #[[NOINLINE]] = { {{.*noinline.*}} }
 
 void seh_in_noexcept() noexcept { __try {} __finally {} }
+
+#if defined(ERR1)
+void seh_unwinding() { // expected-error{{cannot use SEH '__try' in blocks}}
+  __try {
+HasCleanup x;
+  } __except (1) {
+  }
+}
+#elif defined(ERR2)
+void seh_unwinding() { // expected-error{{cannot use SEH '__try' in blocks}}
+  __try {
+  } __except (1) {
+HasCleanup x;
+  }
+}
+#endif

``




https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-21 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From e1a11aa30ccf63162de6f7d9507460db9614362b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/3] Use sema

---
 clang/lib/Sema/SemaStmt.cpp   | 61 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 42 ++
 2 files changed, 103 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..a32d5c37b4605 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,55 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(const Stmt *S) {
+  if (!S)
+return nullptr;
+
+  llvm::SmallVector Worklist;
+  Worklist.push_back(S);
+
+  while (!Worklist.empty()) {
+const Stmt *Cur = Worklist.pop_back_val();
+if (!Cur)
+  continue;
+
+if (isa(Cur))
+  return nullptr;
+
+if (isa(Cur) || isa(Cur) ||
+isa(Cur)) {
+  return Cur;
+}
+
+if (isa(Cur) || isa(Cur)) {
+  return Cur;
+}
+
+if (const auto *DS = dyn_cast(Cur)) {
+  for (const Decl *D : DS->decls()) {
+if (const auto *VD = dyn_cast(D)) {
+  QualType QT = VD->getType();
+  if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) {
+if (const CXXDestructorDecl *DD = RD->getDestructor()) {
+  if (!DD->isTrivial())
+return DS;
+}
+  }
+}
+  }
+}
+
+for (const Stmt *Child : Cur->children())
+  if (Child)
+Worklist.push_back(Child);
+  }
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4531,6 +4580,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   ? "'try'"
   : "'@try'");
 }
+if (const Stmt *Offending = findNonTrivialObject(TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
   }
 
   FSI->setHasSEHTry(TryLoc);
@@ -4562,6 +4615,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..bdc369ff767da 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,45 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+CheckError::Check("Caught a C-based exception."); // 
expected-error{{cannot use SEH '__try' in blocks}}
+  }
+  return e;
+}
+
+// has throw should work
+int foo__except_with_throw(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+throw(CheckError::Check("Caught a C-based exception."));
+  }
+  return e;
+}

>From 86db2c253868a1fb867497c88ee06a2d938696c1 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Sun, 21 Dec 2025 16:24:55 +0800
Subject: [PATCH 2/3] Revert "Use sema"

This reverts commit e1a11aa30ccf63162de6f7d9507460db9614362b.
---
 clang/lib/Sema/SemaStmt.cpp   | 61 ---
 clang/test/SemaCXX/exceptions-seh.cpp | 42 --
 2 files changed, 103 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index a32d5c37b4605..1b1643250d05e 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,55 +4515,6 @@ void Sema::DiagnoseExceptionUs

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

GkvJwa wrote:

I continued debugging it, SEH && object unwinding, When both conditions are 
present
EmitCXXTemporary -> pushDestroy(The fourth arg is destroyCXXObject)
```
clang::CodeGen::EHScopeStack::pushCleanup Line 209
 clang::CodeGen::EHScopeStack::pushCleanup  Line 293
  clang::CodeGen::CodeGenFunction::pushFullExprCleanup Line 912
   clang::CodeGen::CodeGenFunction::pushDestroy Line 2297
 clang::CodeGen::CodeGenFunction::EmitCXXTemporary Line 1343

void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
   QualType TempType,
   Address Ptr) {
  pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
  /*useEHCleanup*/ true);
}
```

This arg can be used to directly determine whether it's an object, but it's not 
passed in `pushCleanup`.
```
  template  void pushCleanup(CleanupKind Kind, As... A) {
static_assert(alignof(T) <= ScopeStackAlignment,
  "Cleanup's alignment is too large.");
void *Buffer = pushCleanup(Kind, sizeof(T));
Cleanup *Obj = new (Buffer) T(A...); // here
(void) Obj;
  }
```

This prevents us from checking directly, or we can check in EmitCXXTemporary to 
see if it's feasible?


https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

MuellerMP wrote:

We specifically care about `IsEHCleanup` and not `IsNormalCleanup` for this 
diagnostic

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/GkvJwa edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/GkvJwa edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/GkvJwa edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

GkvJwa wrote:

If change here, It seems that only check `IsNormalCleanup == true`, and then a 
diagnosis can be made.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-19 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

MuellerMP wrote:

I can not really argue about Sema since I'm less familiar with that code but 
regarding a CodeGen fix: you can look up `EHScopeStack::pushCleanup`. This is 
the single instance where `EmitSehCppScopeBegin` is called in the default 
frontend (not CIR). If you check here for SEH personality (maybe reuse 
`getSEHPersonalityMSVC`?) you can emit the diagnostic on the function defintion 
sorta like this:
```c++
CGF->CGM.getDiags().Report(CGF->CurFuncDecl->getLocation(), 
diag::the_correct_seh_diagnostic)
```

MSVC also just seems to emit the diagnostic on the function definition line. So 
the handling would be conforming with the MSVC way.


https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 2e34318cd3fbffedbd231239d9f99a0907442970 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/5] Add test and skip Borland

---
 clang/lib/Sema/SemaStmt.cpp   | 70 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 30 
 2 files changed, 100 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c562d15b0338c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4586,17 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
 
   FSI->setHasSEHTry(TryLoc);
 
+  // Disallow non-trivial C++ objects in an SEH __try block as well. If the
+  // try block contains temporaries or local objects with non-trivial
+  // destructors, emit the same diagnostic and fail parsing the try. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
+
   // Reject __try in Obj-C methods, blocks, and captured decls, since we don't
   // track if they use SEH.
   DeclContext *DC = CurContext;
@@ -4562,6 +4624,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..0a008aeb5721e 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,33 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+Ch

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff origin/main HEAD --extensions cpp -- 
clang/lib/Sema/SemaStmt.cpp clang/test/SemaCXX/exceptions-seh.cpp 
--diff_from_common_commit
``

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:





View the diff from clang-format here.


``diff
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 3732179e3..2882c3a60 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4580,7 +4580,7 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   ? "'try'"
   : "'@try'");
 }
-
+
 if (const Stmt *Offending = findNonTrivialObject(TryBlock)) {
   return StmtError(
   Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));

``




https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 2e34318cd3fbffedbd231239d9f99a0907442970 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/4] Add test and skip Borland

---
 clang/lib/Sema/SemaStmt.cpp   | 70 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 30 
 2 files changed, 100 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c562d15b0338c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4586,17 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
 
   FSI->setHasSEHTry(TryLoc);
 
+  // Disallow non-trivial C++ objects in an SEH __try block as well. If the
+  // try block contains temporaries or local objects with non-trivial
+  // destructors, emit the same diagnostic and fail parsing the try. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
+
   // Reject __try in Obj-C methods, blocks, and captured decls, since we don't
   // track if they use SEH.
   DeclContext *DC = CurContext;
@@ -4562,6 +4624,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..0a008aeb5721e 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,33 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+Ch

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

MuellerMP wrote:

It would be `EnterSEHTryStmt` and not `EnterCXXTryStmt` in this case.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

GkvJwa wrote:

I think optimizing recursion in Sema might be a better approach than making 
modifications in `CodeGenFunction::EnterCXXTryStmt`. Is that what you mean too?

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

MuellerMP wrote:

Also the reason why I suggest emitting a diagnostic rather than handling this 
in the backend is that there are a lot of open choices if you mix C++ EHa and 
SEH like e.g. what personality is chosen. The borland compiler might have a 
working solution which you could look at, but just handling this the way MSVC 
does seem to be a lot easier.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits

https://github.com/MuellerMP edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

MuellerMP wrote:

@GkvJwa I dont think we need to emulate the error behavior of MSVC 1:1.
It is enough if we detect the use of SEH along with object 
destruction/unwinding and than emit a diagnostic since the LLVM backend can not 
handle this as it seems to be implemented with this exact MSVC SEH restriction 
in mind.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-18 Thread via cfe-commits


@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {

GkvJwa wrote:

I don't seem to have seen a complete list of C2712 errors, and I'm not sure if 
Microsoft provides one.
With more cases, it might be possible to handle this better.


https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 2e34318cd3fbffedbd231239d9f99a0907442970 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/3] Add test and skip Borland

---
 clang/lib/Sema/SemaStmt.cpp   | 70 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 30 
 2 files changed, 100 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c562d15b0338c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4586,17 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
 
   FSI->setHasSEHTry(TryLoc);
 
+  // Disallow non-trivial C++ objects in an SEH __try block as well. If the
+  // try block contains temporaries or local objects with non-trivial
+  // destructors, emit the same diagnostic and fail parsing the try. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
+
   // Reject __try in Obj-C methods, blocks, and captured decls, since we don't
   // track if they use SEH.
   DeclContext *DC = CurContext;
@@ -4562,6 +4624,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..0a008aeb5721e 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,33 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+Ch

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 2e34318cd3fbffedbd231239d9f99a0907442970 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH 1/2] Add test and skip Borland

---
 clang/lib/Sema/SemaStmt.cpp   | 70 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 30 
 2 files changed, 100 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c562d15b0338c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4586,17 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
 
   FSI->setHasSEHTry(TryLoc);
 
+  // Disallow non-trivial C++ objects in an SEH __try block as well. If the
+  // try block contains temporaries or local objects with non-trivial
+  // destructors, emit the same diagnostic and fail parsing the try. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
+
   // Reject __try in Obj-C methods, blocks, and captured decls, since we don't
   // track if they use SEH.
   DeclContext *DC = CurContext;
@@ -4562,6 +4624,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..0a008aeb5721e 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,33 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+Ch

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 2e34318cd3fbffedbd231239d9f99a0907442970 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Thu, 18 Dec 2025 00:30:02 +0800
Subject: [PATCH] Add test and skip Borland

---
 clang/lib/Sema/SemaStmt.cpp   | 70 +++
 clang/test/SemaCXX/exceptions-seh.cpp | 30 
 2 files changed, 100 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c562d15b0338c 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,57 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4586,17 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
 
   FSI->setHasSEHTry(TryLoc);
 
+  // Disallow non-trivial C++ objects in an SEH __try block as well. If the
+  // try block contains temporaries or local objects with non-trivial
+  // destructors, emit the same diagnostic and fail parsing the try. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, TryBlock)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
+
   // Reject __try in Obj-C methods, blocks, and captured decls, since we don't
   // track if they use SEH.
   DeclContext *DC = CurContext;
@@ -4562,6 +4624,14 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  // Disallow non-trivial C++ objects in an SEH __except handler. Skip
+  // this diagnostic when Borland extensions are enabled.
+  if (!getLangOpts().Borland) {
+if (const Stmt *Offending = findNonTrivialObject(*this, Block)) {
+  return StmtError(
+  Diag(Offending->getBeginLoc(), diag::err_seh_try_outside_functions));
+}
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 
diff --git a/clang/test/SemaCXX/exceptions-seh.cpp 
b/clang/test/SemaCXX/exceptions-seh.cpp
index 02bb786160dcf..0a008aeb5721e 100644
--- a/clang/test/SemaCXX/exceptions-seh.cpp
+++ b/clang/test/SemaCXX/exceptions-seh.cpp
@@ -126,3 +126,33 @@ void instantiate_dependent_filter() {
   dependent_filter();
   dependent_filter(); // expected-note {{requested here}}
 }
+
+int puts(const char *);
+class CheckError {
+public:
+ static CheckError Check(const char* msg);
+
+ ~CheckError();
+};
+
+int foo__try(const int* f) {
+  int e;
+  __try {
+CheckError::Check("null pointer"); // expected-error{{cannot use SEH 
'__try' in blocks}}
+e = *f;
+  } __except (1) {
+puts("Caught a C-based exception.");
+  }
+  return e;
+}
+
+int foo__except(const int* f) {
+  int e;
+  __try {
+puts("null pointer");
+e = *f;
+  } __except (1) {
+CheckE

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 1dc5b737beeb3062bafc6e8221aeb9cef9b1b77b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 01:02:42 +0800
Subject: [PATCH 1/5] Add check object

---
 clang/lib/Sema/SemaStmt.cpp | 43 +
 1 file changed, 43 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c64029f269c2b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }
 
+static bool containsNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return false;
+
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return true;
+  }
+}
+  }
+}
+  }
+
+  if (const Expr *E = dyn_cast(Node)) {
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return true;
+}
+  }
+}
+  }
+
+  // children.
+  for (const Stmt *Child : Node->children())
+if (containsNonTrivialObject(S, Child))
+  return true;
+
+  return false;
+}
+
 StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
  Stmt *Block) {
   assert(FilterExpr && Block);
@@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  if (containsNonTrivialObject(*this, Block)) {
+Diag(Loc, diag::err_seh_try_outside_functions);
+return StmtError();
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 

>From adfa51086425c0f9400342f04746428851b217b8 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 23:02:49 +0800
Subject: [PATCH 2/5] Check try block and CXXThrow

---
 clang/lib/Sema/SemaStmt.cpp | 106 ++--
 1 file changed, 65 insertions(+), 41 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c64029f269c2b..c312c445b1fb3 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,58 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4587,15 @@ S

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

MuellerMP wrote:

@GkvJwa you can leave the __try.cpp test as is and just check for borland in 
your fix

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 1dc5b737beeb3062bafc6e8221aeb9cef9b1b77b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 01:02:42 +0800
Subject: [PATCH 1/4] Add check object

---
 clang/lib/Sema/SemaStmt.cpp | 43 +
 1 file changed, 43 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c64029f269c2b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }
 
+static bool containsNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return false;
+
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return true;
+  }
+}
+  }
+}
+  }
+
+  if (const Expr *E = dyn_cast(Node)) {
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return true;
+}
+  }
+}
+  }
+
+  // children.
+  for (const Stmt *Child : Node->children())
+if (containsNonTrivialObject(S, Child))
+  return true;
+
+  return false;
+}
+
 StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
  Stmt *Block) {
   assert(FilterExpr && Block);
@@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  if (containsNonTrivialObject(*this, Block)) {
+Diag(Loc, diag::err_seh_try_outside_functions);
+return StmtError();
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 

>From adfa51086425c0f9400342f04746428851b217b8 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 23:02:49 +0800
Subject: [PATCH 2/4] Check try block and CXXThrow

---
 clang/lib/Sema/SemaStmt.cpp | 106 ++--
 1 file changed, 65 insertions(+), 41 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c64029f269c2b..c312c445b1fb3 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,58 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4587,15 @@ S

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 1dc5b737beeb3062bafc6e8221aeb9cef9b1b77b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 01:02:42 +0800
Subject: [PATCH 1/3] Add check object

---
 clang/lib/Sema/SemaStmt.cpp | 43 +
 1 file changed, 43 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c64029f269c2b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }
 
+static bool containsNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return false;
+
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return true;
+  }
+}
+  }
+}
+  }
+
+  if (const Expr *E = dyn_cast(Node)) {
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return true;
+}
+  }
+}
+  }
+
+  // children.
+  for (const Stmt *Child : Node->children())
+if (containsNonTrivialObject(S, Child))
+  return true;
+
+  return false;
+}
+
 StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
  Stmt *Block) {
   assert(FilterExpr && Block);
@@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  if (containsNonTrivialObject(*this, Block)) {
+Diag(Loc, diag::err_seh_try_outside_functions);
+return StmtError();
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 

>From adfa51086425c0f9400342f04746428851b217b8 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 23:02:49 +0800
Subject: [PATCH 2/3] Check try block and CXXThrow

---
 clang/lib/Sema/SemaStmt.cpp | 106 ++--
 1 file changed, 65 insertions(+), 41 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c64029f269c2b..c312c445b1fb3 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,58 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4587,15 @@ S

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff origin/main HEAD --extensions cpp -- 
clang/lib/Sema/SemaStmt.cpp --diff_from_common_commit
``

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:





View the diff from clang-format here.


``diff
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c312c445b..cc08cc126 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,7 +4515,6 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
-
 // Walk the statement subtree and return the first statement that
 // contains a non-trivial C++ object that would require destruction at
 // scope exit, or nullptr if none was found.

``




https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-17 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 1dc5b737beeb3062bafc6e8221aeb9cef9b1b77b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 01:02:42 +0800
Subject: [PATCH 1/2] Add check object

---
 clang/lib/Sema/SemaStmt.cpp | 43 +
 1 file changed, 43 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c64029f269c2b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }
 
+static bool containsNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return false;
+
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return true;
+  }
+}
+  }
+}
+  }
+
+  if (const Expr *E = dyn_cast(Node)) {
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return true;
+}
+  }
+}
+  }
+
+  // children.
+  for (const Stmt *Child : Node->children())
+if (containsNonTrivialObject(S, Child))
+  return true;
+
+  return false;
+}
+
 StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
  Stmt *Block) {
   assert(FilterExpr && Block);
@@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  if (containsNonTrivialObject(*this, Block)) {
+Diag(Loc, diag::err_seh_try_outside_functions);
+return StmtError();
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 

>From adfa51086425c0f9400342f04746428851b217b8 Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 23:02:49 +0800
Subject: [PATCH 2/2] Check try block and CXXThrow

---
 clang/lib/Sema/SemaStmt.cpp | 106 ++--
 1 file changed, 65 insertions(+), 41 deletions(-)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index c64029f269c2b..c312c445b1fb3 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4515,6 +4515,58 @@ void Sema::DiagnoseExceptionUse(SourceLocation Loc, bool 
IsTry) {
 targetDiag(Loc, diag::err_exceptions_disabled) << (IsTry ? "try" : 
"throw");
 }
 
+
+// Walk the statement subtree and return the first statement that
+// contains a non-trivial C++ object that would require destruction at
+// scope exit, or nullptr if none was found.
+static const Stmt *findNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return nullptr;
+
+  // Check for declarations of local variables with non-trivial destructors.
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return DS;
+  }
+}
+  }
+}
+  }
+
+  // Check for expressions that materialize temporaries or otherwise
+  // produce prvalue/xvalue C++ objects that will require destruction.
+  if (const Expr *E = dyn_cast(Node)) {
+// A throw-expression creates an exception object as part of throwing and
+// doesn't create a temporary that lives until the end of the handler
+// scope; ignore it when checking for non-trivial temporaries.
+if (isa(E))
+  return nullptr;
+
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return E;
+}
+  }
+}
+  }
+
+  // Recurse into children.
+  for (const Stmt *Child : Node->children())
+if (const Stmt *SWith = findNonTrivialObject(S, Child))
+  return SWith;
+
+  return nullptr;
+}
+
 StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc,
   Stmt *TryBlock, Stmt *Handler) {
   assert(TryBlock && Handler);
@@ -4535,6 +4587,15 @@ S

[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

MuellerMP wrote:

@GkvJwa Regarding the failing test: I have to apologize. It seems there is some 
Borland C++ compatibility switch that I did not know about that allows these 
constructs to be parsed at least.
Regarding compilation this test does seem to fail very quickly though: 
https://godbolt.org/z/6eGfrr4Kn .
I assume the Borland C++ switch does not have any maintainer and just has some 
parser tests.

I would suggest emitting the diagnostic only for non Borland C++. 
Regarding the Borland behavior: it might make even sense to deprecate Borland 
C++ support since its in such a broken state? But that really is not for me to 
decide.

@efriedma-quic Can you confirm that we should move ahead with this diagnostic 
for non Borland C++?
An alternative would be, like I said earlier, to support this SEH & C++ mixing 
in the SEH state numbering algo. In the latter case it might make sense to 
investigate what the Borland C++ compiler emits for the test code (especially 
which personality routine is chosen - since that is not an obvious decision 
IMO).

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

github-actions[bot] wrote:


# :penguin: Linux x64 Test Results

* 85151 tests passed
* 1176 tests skipped
* 1 test failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.SemaCXX/__try.cpp

```
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 
-internal-isystem 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/22/include
 -nostdsysteminc -triple x86_64-windows -fsyntax-only -verify 
-fborland-extensions -fcxx-exceptions 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaCXX/__try.cpp
# executed command: 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/bin/clang -cc1 
-internal-isystem 
/home/gha/actions-runner/_work/llvm-project/llvm-project/build/lib/clang/22/include
 -nostdsysteminc -triple x86_64-windows -fsyntax-only -verify 
-fborland-extensions -fcxx-exceptions 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaCXX/__try.cpp
# .---command stderr
# | error: 'expected-error' diagnostics seen but not expected: 
# |   File 
/home/gha/actions-runner/_work/llvm-project/llvm-project/clang/test/SemaCXX/__try.cpp
 Line 42: cannot use SEH '__try' in blocks, captured regions, or Obj-C method 
decls
# | 1 error generated.
# `-
# error: command failed with exit status: 1

--

```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

github-actions[bot] wrote:


# :window: Windows x64 Test Results

* 51560 tests passed
* 877 tests skipped
* 1 test failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.SemaCXX/__try.cpp

```
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 1
c:\_work\llvm-project\llvm-project\build\bin\clang.exe -cc1 -internal-isystem 
C:\_work\llvm-project\llvm-project\build\lib\clang\22\include -nostdsysteminc 
-triple x86_64-windows -fsyntax-only -verify -fborland-extensions 
-fcxx-exceptions C:\_work\llvm-project\llvm-project\clang\test\SemaCXX\__try.cpp
# executed command: 'c:\_work\llvm-project\llvm-project\build\bin\clang.exe' 
-cc1 -internal-isystem 
'C:\_work\llvm-project\llvm-project\build\lib\clang\22\include' -nostdsysteminc 
-triple x86_64-windows -fsyntax-only -verify -fborland-extensions 
-fcxx-exceptions 
'C:\_work\llvm-project\llvm-project\clang\test\SemaCXX\__try.cpp'
# .---command stderr
# | error: 'expected-error' diagnostics seen but not expected: 
# |   File C:\_work\llvm-project\llvm-project\clang\test\SemaCXX\__try.cpp Line 
42: cannot use SEH '__try' in blocks, captured regions, or Obj-C method decls
# | 1 error generated.
# `-
# error: command failed with exit status: 1

--

```


If these failures are unrelated to your changes (for example tests are broken 
or flaky at HEAD), please open an issue at 
https://github.com/llvm/llvm-project/issues and add the `infrastructure` label.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

https://github.com/GkvJwa edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

https://github.com/GkvJwa edited 
https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

GkvJwa wrote:

> I would also like to note that using `try{}catch(...){}` instead of 
> `__try{}__except(1){}` is a basically semantically equivalent workaround for 
> this issue.

On Windows, the latter is the SEH.  The `1` can be replaced with actual 
exceptions(GetExceptionCode() == ?), which the former cannot do. That's why we 
need to specifically use SEH.

Also, if you have time, review it again. If there are no issues, I will add 
test.

https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: None (GkvJwa)


Changes

Consider the following code:
```

#include 

class CheckError {
 public:
  static CheckError Check();

  ~CheckError();
};

void Foo(const int* p) {
  int d = 0;
  __try {
d = *p;
  } __except (EXCEPTION_EXECUTE_HANDLER) {
::CheckError::Check();
  }
}

```

The following error will occur in mscv.
```
error C2712: Cannot use __try in functions that require object unwinding
```

However, using LLVM /EHa will cause it to crash.
```
llvm::SmallVectorTemplateCommon::operator[](unsigned
 __int64 idx) Line 295  C++
llvm::calculateSEHStateForAsynchEH(const llvm::BasicBlock * BB, int State, 
llvm::WinEHFuncInfo & EHInfo) Line 346   C++
llvm::calculateSEHStateNumbers(const llvm::Function * Fn, llvm::WinEHFuncInfo 
& FuncInfo) Line 612  C++
llvm::FunctionLoweringInfo::set(const llvm::Function & fn, 
llvm::MachineFunction & mf, llvm::SelectionDAG * DAG) Line 114   C++
llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction & mf) 
Line 588   C++
```

This patch is compatible with the crash.

---
Full diff: https://github.com/llvm/llvm-project/pull/172287.diff


1 Files Affected:

- (modified) clang/lib/Sema/SemaStmt.cpp (+43) 


``diff
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c64029f269c2b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }
 
+static bool containsNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return false;
+
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return true;
+  }
+}
+  }
+}
+  }
+
+  if (const Expr *E = dyn_cast(Node)) {
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return true;
+}
+  }
+}
+  }
+
+  // children.
+  for (const Stmt *Child : Node->children())
+if (containsNonTrivialObject(S, Child))
+  return true;
+
+  return false;
+}
+
 StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
  Stmt *Block) {
   assert(FilterExpr && Block);
@@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  if (containsNonTrivialObject(*this, Block)) {
+Diag(Loc, diag::err_seh_try_outside_functions);
+return StmtError();
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 

``




https://github.com/llvm/llvm-project/pull/172287
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [WinEH] Fix crash, object unwinding in the except block (PR #172287)

2025-12-16 Thread via cfe-commits

https://github.com/GkvJwa updated 
https://github.com/llvm/llvm-project/pull/172287

>From 1dc5b737beeb3062bafc6e8221aeb9cef9b1b77b Mon Sep 17 00:00:00 2001
From: GkvJwa 
Date: Wed, 17 Dec 2025 01:02:42 +0800
Subject: [PATCH] Add check object

---
 clang/lib/Sema/SemaStmt.cpp | 43 +
 1 file changed, 43 insertions(+)

diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 1b1643250d05e..c64029f269c2b 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -4553,6 +4553,45 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, 
SourceLocation TryLoc,
   return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
 }
 
+static bool containsNonTrivialObject(Sema &S, const Stmt *Node) {
+  (void)S;
+  if (!Node)
+return false;
+
+  if (const DeclStmt *DS = dyn_cast(Node)) {
+for (const Decl *D : DS->decls()) {
+  if (const VarDecl *VD = dyn_cast(D)) {
+QualType T = VD->getType();
+if (const RecordType *RT = T->getAs()) {
+  if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+  return true;
+  }
+}
+  }
+}
+  }
+
+  if (const Expr *E = dyn_cast(Node)) {
+QualType T = E->getType();
+if (T->isRecordType() && E->getValueKind() != VK_LValue) {
+  if (const RecordType *RT = T->getAs()) {
+if (const CXXRecordDecl *RD = RT->getAsCXXRecordDecl()) {
+  if (RD->hasDefinition() && !RD->hasTrivialDestructor())
+return true;
+}
+  }
+}
+  }
+
+  // children.
+  for (const Stmt *Child : Node->children())
+if (containsNonTrivialObject(S, Child))
+  return true;
+
+  return false;
+}
+
 StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr,
  Stmt *Block) {
   assert(FilterExpr && Block);
@@ -4562,6 +4601,10 @@ StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, 
Expr *FilterExpr,
 Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral)
 << FTy);
   }
+  if (containsNonTrivialObject(*this, Block)) {
+Diag(Loc, diag::err_seh_try_outside_functions);
+return StmtError();
+  }
   return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block);
 }
 

___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits