================
@@ -2096,6 +2115,142 @@ static void compileFunction(InterpState &S, const 
Function *Func) {
       .compileFunc(Definition, const_cast<Function *>(Func));
 }
 
+// We have a saved thrown value in InterpState.
+// Now try to catch that value in the current function.
+// If no corresponding catch handler is found, jump to the
+// AfterRet op at the end of the function.
+static bool catchException(InterpState &S, CodePtr OpPC) {
+  assert(S.getContext().ExceptionsEnabled);
+  assert(S.ThrownValue);
+  assert(!S.ThrownValue->Caught);
+
+  // We've reached the bottom frame. We can't go any higher, so diagnose
+  // an uncaught exception.
+  const Function *CurrFunction = S.Current->getFunction();
+  if (!CurrFunction) {
+    assert(S.Current->isBottomFrame());
+    if (!S.checkingPotentialConstantExpression())
+      return diagnoseUncaughtException(S, OpPC);
+    return false;
+  }
+
+  unsigned CodeOffset = S.PC - CurrFunction->getCodeBegin();
+  std::optional<ExceptionTableEntry> CatchEntry =
+      CurrFunction->findCatchHandler(CodeOffset, S.ThrownValue->Ty,
+                                     S.getASTContext());
+
+  if (!CatchEntry) {
+    // We didn't find an appropriate catch handler in the current function.
+    // Skip to the end of the function.
+    bool CanThrow = S.Current->getFunction()
+                        ->getDecl()
+                        ->getType()
+                        ->getAs<FunctionProtoType>()
+                        ->canThrow();
+    if (!CanThrow) {
+      S.CCEDiag(S.Current->getSource(OpPC),
+                diag::note_constexpr_exception_in_noexcept_func);
+      return false;
+    }
+    // Jump to the end of the function. The calling function will handle
+    // catching the exception.
+    S.PC = S.Current->getFunction()->getCodeEnd() - align(sizeof(Opcode));
+#ifndef NDEBUG
+    CodePtr PCCopy = S.PC;
+    Opcode Op = PCCopy.read<Opcode>();
+    assert(Op == OP_AfterRet);
+#endif
+    return true;
+  }
+
+  // We *did* find a catch handler. We now need to cast the thrown value to
+  // the correct type, if necessary.
+
+  // NB: CaughtType may be null (for catch-all handlers).
+  const Type *CaughtType = CatchEntry->CatchType;
+  const Type *ThrownType = S.ThrownValue->Ty;
+  assert(ThrownType);
+
+  // There might be some values left on the stack that have been added in
+  // between entering the try{} block and the throw statement. We need to
+  // remove all of those so the stack is in a proper state after the catch
+  // handler finishes.
+  while (S.Stk.size() != S.ThrowTrapStackSize) {
----------------
zwuis wrote:

This doesn't recover `ThrowTrapStackSize` for `try` in caller correctly.

<details>
<summary>Reproducer</summary>

```cpp
constexpr int a(int) { throw 1; }
constexpr int b(int x) {
  try {
    a(x);
  } catch (int) {
    throw;
  }
  return 0;
}
constexpr int c() {
  try {
    b(5);
  } catch (int) {
    return 10;
  }
  return 1;
}
static_assert(c() == 10);
```

</details>

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

Reply via email to