llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

Just parking this here as a draft so I don't forget about it again.

---

Patch is 71.73 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/189410.diff


29 Files Affected:

- (modified) clang/include/clang/Basic/DiagnosticASTKinds.td (+3) 
- (modified) clang/lib/AST/ByteCode/ByteCodeEmitter.cpp (+2-1) 
- (modified) clang/lib/AST/ByteCode/ByteCodeEmitter.h (+9) 
- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+201-22) 
- (modified) clang/lib/AST/ByteCode/Compiler.h (+3) 
- (modified) clang/lib/AST/ByteCode/Context.cpp (+3) 
- (modified) clang/lib/AST/ByteCode/Context.h (+2) 
- (modified) clang/lib/AST/ByteCode/Disasm.cpp (+8) 
- (modified) clang/lib/AST/ByteCode/EvalEmitter.h (+10) 
- (added) clang/lib/AST/ByteCode/Exceptions.cpp (+56) 
- (added) clang/lib/AST/ByteCode/Exceptions.h (+34) 
- (modified) clang/lib/AST/ByteCode/Function.cpp (+9) 
- (modified) clang/lib/AST/ByteCode/Function.h (+9-2) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+154-10) 
- (modified) clang/lib/AST/ByteCode/Interp.h (+84-6) 
- (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+1) 
- (modified) clang/lib/AST/ByteCode/InterpFrame.h (-4) 
- (modified) clang/lib/AST/ByteCode/InterpStack.cpp (+6) 
- (modified) clang/lib/AST/ByteCode/InterpStack.h (+3) 
- (modified) clang/lib/AST/ByteCode/InterpState.h (+18) 
- (modified) clang/lib/AST/ByteCode/Opcodes.td (+40-1) 
- (modified) clang/lib/AST/ByteCode/PrimType.h (+9) 
- (modified) clang/lib/AST/ByteCode/Source.h (+2) 
- (modified) clang/lib/AST/CMakeLists.txt (+1) 
- (modified) clang/test/AST/ByteCode/cxx20.cpp (+7-8) 
- (modified) clang/test/AST/ByteCode/cxx23.cpp (+2-2) 
- (added) clang/test/AST/ByteCode/exceptions.cpp (+1076) 
- (modified) clang/test/AST/ByteCode/invalid.cpp (+2-28) 
- (modified) clang/utils/TableGen/ClangOpcodesEmitter.cpp (+12-3) 


``````````diff
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index bde418695f647..9318390db1da2 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -406,6 +406,9 @@ def note_constexpr_infer_alloc_token_no_metadata : Note<
   "could not get token metadata for inferred type">;
 def note_constexpr_infer_alloc_token_stateful_mode
     : Note<"stateful alloc token mode not supported in constexpr">;
+def note_constexpr_uncaught_exception : Note<"uncaught exception of type %0: 
'%1'">;
+def note_constexpr_exception_in_noexcept_func : Note<"uncaught exception in 
noexcept function">;
+def note_constexpr_no_active_exception : Note<"throw with no caught exception 
active">;
 
 def warn_attribute_needs_aggregate : Warning<
   "%0 attribute is ignored in non-aggregate type %1">,
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
index 393b8481fecd1..17cf076c52851 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp
@@ -85,7 +85,8 @@ void ByteCodeEmitter::compileFunc(const FunctionDecl 
*FuncDecl,
 
   // Set the function's code.
   Func->setCode(FuncDecl, NextLocalOffset, std::move(Code), std::move(SrcMap),
-                std::move(Scopes), FuncDecl->hasBody(), IsValid);
+                std::move(Scopes), std::move(ExceptionTable),
+                FuncDecl->hasBody(), IsValid);
   Func->setIsFullyCompiled(true);
 }
 
diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h 
b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
index 34342e53837b9..0cdd5d2d1dfa5 100644
--- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h
+++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h
@@ -82,6 +82,14 @@ class ByteCodeEmitter {
   llvm::SmallVector<SmallVector<Local, 8>, 2> Descriptors;
   std::optional<SourceInfo> LocOverride = std::nullopt;
 
+  unsigned currentCodeSize() const { return Code.size(); }
+
+  void registerExceptionHandler(unsigned From, unsigned To, unsigned Target,
+                                UnsignedOrNone DeclOffset, const Type *T) {
+    ExceptionTable.push_back(
+        ExceptionTableEntry{From, To, Target, DeclOffset, T});
+  }
+
 private:
   /// Current compilation context.
   Context &Ctx;
@@ -97,6 +105,7 @@ class ByteCodeEmitter {
   llvm::DenseMap<LabelTy, llvm::SmallVector<unsigned, 5>> LabelRelocs;
   /// Program code.
   llvm::SmallVector<std::byte> Code;
+  llvm::SmallVector<ExceptionTableEntry> ExceptionTable;
   /// Opcode to expression mapping.
   SourceMap SrcMap;
 
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index 95f9a2f507335..f826cb4f8c096 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -37,6 +37,17 @@ static std::optional<bool> getBoolValue(const Expr *E) {
   return std::nullopt;
 }
 
+[[maybe_unused]] static bool blockEndsInReturn(const Stmt *S) {
+  if (isa<ReturnStmt>(S))
+    return true;
+
+  if (const auto *CS = dyn_cast<CompoundStmt>(S); CS && !CS->body_empty()) {
+    return isa<ReturnStmt>(CS->body_back());
+  }
+
+  return false;
+}
+
 /// Scope used to handle temporaries in toplevel variable declarations.
 template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
 public:
@@ -3471,10 +3482,136 @@ bool Compiler<Emitter>::VisitPredefinedExpr(const 
PredefinedExpr *E) {
 
 template <class Emitter>
 bool Compiler<Emitter>::VisitCXXThrowExpr(const CXXThrowExpr *E) {
-  if (E->getSubExpr() && !this->discard(E->getSubExpr()))
+  const Expr *SubExpr = E->getSubExpr();
+  if (!Ctx.ExceptionsEnabled) {
+    if (SubExpr && !this->discard(SubExpr))
+      return false;
+    return this->emitInvalid(E);
+  }
+
+  if (!SubExpr)
+    return this->emitReThrow(E);
+
+  QualType ExceptionType = SubExpr->getType();
+  OptPrimType ExceptionT = classify(SubExpr);
+
+  const Descriptor *Desc;
+  if (ExceptionT)
+    Desc = P.createDescriptor(SubExpr, *ExceptionT);
+  else
+    Desc = P.createDescriptor(SubExpr, ExceptionType.getTypePtr(), 
std::nullopt,
+                              /*IsConst=*/false);
+
+  if (!this->emitAllocException(Desc, E))
+    return false;
+
+  if (ExceptionT) {
+    if (!this->visit(SubExpr))
+      return false;
+    if (!this->emitInit(*ExceptionT, E))
+      return false;
+  } else {
+    if (!this->visitInitializer(SubExpr))
+      return false;
+  }
+
+  OptPrimType T = classify(E->getSubExpr()->getType());
+  if (!this->emitSaveException(T.value_or(PT_Ptr), ExceptionType.getTypePtr(),
+                               (bool)T, E))
     return false;
 
-  return this->emitInvalid(E);
+  this->VarScope->destroyLocals();
+
+  return this->emitThrow(E);
+}
+
+template <class Emitter>
+bool Compiler<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
+  if (!Ctx.ExceptionsEnabled) {
+    // Ignore all handlers.
+    return this->visitStmt(S->getTryBlock());
+  }
+
+  unsigned NumHandlers = S->getNumHandlers();
+
+  // When an exception is thrown in the middle of a try{} block, we use this
+  // throw trap to pop all values from the stack that have been added during
+  // the try block before the throw.
+  if (!this->emitThrowTrap(S))
+    return false;
+
+  // For the try block, we record the bytecode offset before and
+  // after it. When an exception is thrown, we check if the offset
+  // at that point is between the start/end of the appropriate catch
+  // handler for this try block. If we find such a handler, we jump to it.
+  unsigned TryBlockStart = this->currentCodeSize();
+  {
+    const auto *TryBlock = cast<CompoundStmt>(S->getTryBlock());
+    if (!this->visitStmt(TryBlock))
+      return false;
+  }
+  unsigned TryBlockEnd = this->currentCodeSize();
+
+  // Jump after handlers if nothing was thrown.
+  LabelTy EndLabel = this->getLabel();
+  this->jump(EndLabel, S);
+
+  // Register and emit all handlers.
+  for (unsigned I = 0; I != NumHandlers; ++I) {
+    const CXXCatchStmt *Handler = S->getHandler(I);
+    const Stmt *HandlerBlock = Handler->getHandlerBlock();
+    const VarDecl *ExceptionDecl = Handler->getExceptionDecl();
+    QualType CatchType = Handler->getCaughtType();
+    UnsignedOrNone ExceptionDeclOffset = std::nullopt;
+
+    unsigned HandlerOffset = this->currentCodeSize();
+    if (ExceptionDecl) {
+      if (OptPrimType T = classify(CatchType)) {
+        unsigned LocalOffset = allocateLocalPrimitive(ExceptionDecl, *T,
+                                                      /*IsConst=*/true);
+        if (CatchType->isReferenceType()) {
+          if (!this->emitGetPtrExceptionValue(S))
+            return false;
+        } else {
+          if (!this->emitGetExceptionValue(*T, S))
+            return false;
+        }
+        if (!this->emitSetLocal(*T, LocalOffset, S))
+          return false;
+      } else {
+        UnsignedOrNone LocalOffset = allocateLocal(ExceptionDecl, CatchType);
+        if (!LocalOffset)
+          return false;
+
+        if (!this->emitGetPtrLocal(*LocalOffset, Handler))
+          return false;
+        if (!this->emitGetPtrExceptionValue(Handler))
+          return false;
+        if (!this->emitMemcpy(Handler))
+          return false;
+        if (!this->emitPopPtr(Handler))
+          return false;
+      }
+    } else {
+      // This is a catch-all handler.
+    }
+    const Type *CatchTypePtr = CatchType.getTypePtrOrNull();
+
+    this->registerExceptionHandler(TryBlockStart, TryBlockEnd, HandlerOffset,
+                                   ExceptionDeclOffset, CatchTypePtr);
+    if (!this->visitStmt(HandlerBlock))
+      return false;
+
+    // FIXME: Re-enable this.
+    // if (blockEndsInReturn(TryBlock))
+    // continue;
+    this->jump(EndLabel, S);
+  }
+
+  this->fallthrough(EndLabel);
+  this->emitLabel(EndLabel);
+
+  return true;
 }
 
 template <class Emitter>
@@ -6877,12 +7014,6 @@ bool Compiler<Emitter>::visitAttributedStmt(const 
AttributedStmt *S) {
   return true;
 }
 
-template <class Emitter>
-bool Compiler<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) {
-  // Ignore all handlers.
-  return this->visitStmt(S->getTryBlock());
-}
-
 template <class Emitter>
 bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
   assert(MD->isLambdaStaticInvoker());
@@ -6943,11 +7074,9 @@ bool 
Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) {
     return false;
 
   this->emitCleanup();
-  if (ReturnType)
-    return this->emitRet(*ReturnType, MD);
 
-  // Nothing to do, since we emitted the RVO pointer above.
-  return this->emitRetVoid(MD);
+  bool CanThrow = MD->getType()->getAs<FunctionProtoType>()->canThrow();
+  return this->emitFunctionReturn(MD, ReturnType, CanThrow);
 }
 
 template <class Emitter>
@@ -7153,11 +7282,21 @@ bool Compiler<Emitter>::compileConstructor(const 
CXXConstructorDecl *Ctor) {
         return false;
     }
 
-    if (!visitStmt(Body))
-      return false;
+    if (isa<CompoundStmt>(Body)) {
+      if (!visitStmt(Body))
+        return false;
+    } else {
+      // direct try {} body.
+      LocalScope<Emitter> Scope(this);
+      if (!visitStmt(Body))
+        return false;
+      if (!Scope.destroyLocals())
+        return false;
+    }
   }
 
-  return this->emitRetVoid(SourceInfo{});
+  bool CanThrow = Ctor->getType()->getAs<FunctionProtoType>()->canThrow();
+  return this->emitFunctionReturn(Ctor, ReturnType, CanThrow);
 }
 
 template <class Emitter>
@@ -7207,7 +7346,11 @@ bool Compiler<Emitter>::compileDestructor(const 
CXXDestructorDecl *Dtor) {
     return false;
 
   // FIXME: Virtual bases.
-  return this->emitPopPtr(Dtor) && this->emitRetVoid(Dtor);
+  if (!this->emitPopPtr(Dtor))
+    return false;
+
+  bool CanThrow = Dtor->getType()->getAs<FunctionProtoType>()->canThrow();
+  return this->emitFunctionReturn(Dtor, ReturnType, CanThrow);
 }
 
 template <class Emitter>
@@ -7250,14 +7393,32 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl 
*F) {
   }
 
   // Regular functions.
-  if (const auto *Body = F->getBody())
-    if (!visitStmt(Body))
-      return false;
+  if (const auto *Body = F->getBody()) {
+    if (isa<CompoundStmt>(Body)) {
+      if (!visitStmt(Body))
+        return false;
+    } else {
+      // direct try {} body.
+      LocalScope<Emitter> Scope(this);
+      if (!visitStmt(Body))
+        return false;
+      if (!Scope.destroyLocals())
+        return false;
+    }
+  }
 
   // Emit a guard return to protect against a code path missing one.
-  if (F->getReturnType()->isVoidType())
-    return this->emitRetVoid(SourceInfo{});
-  return this->emitNoRet(SourceInfo{});
+  if (F->getReturnType()->isVoidType()) {
+    if (!this->emitRetVoid(SourceInfo{}))
+      return false;
+  } else if (!this->emitNoRet(SourceInfo{})) {
+    return false;
+  }
+
+  bool CanThrow = F->getType()->getAs<FunctionProtoType>()->canThrow();
+  if (Ctx.ExceptionsEnabled && CanThrow)
+    return this->emitAfterRet(SourceInfo{});
+  return true;
 }
 
 static uint32_t getBitWidth(const Expr *E) {
@@ -8384,6 +8545,24 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const 
CastExpr *E) {
   return true;
 }
 
+template <class Emitter>
+bool Compiler<Emitter>::emitFunctionReturn(const FunctionDecl *FD,
+                                           OptPrimType ReturnType,
+                                           bool CanThrow) {
+  bool NeedsAfterRet = Ctx.ExceptionsEnabled && CanThrow;
+
+  if (!NeedsAfterRet) {
+    if (ReturnType)
+      return this->emitRet(*ReturnType, FD);
+
+    return this->emitRetVoid(FD);
+  }
+
+  if (ReturnType)
+    return this->emitRet(*ReturnType, FD) && this->emitAfterRet(FD);
+  return this->emitRetVoid(FD) && this->emitAfterRet(FD);
+}
+
 /// Replicate a scalar value into every scalar element of an aggregate.
 /// The scalar is stored in a local at \p SrcOffset and a pointer to the
 /// destination must be on top of the interpreter stack. Each element receives
diff --git a/clang/lib/AST/ByteCode/Compiler.h 
b/clang/lib/AST/ByteCode/Compiler.h
index 0a2e75887711d..1cdc2a3dce297 100644
--- a/clang/lib/AST/ByteCode/Compiler.h
+++ b/clang/lib/AST/ByteCode/Compiler.h
@@ -462,6 +462,9 @@ class Compiler : public ConstStmtVisitor<Compiler<Emitter>, 
bool>,
 
   bool refersToUnion(const Expr *E);
 
+  bool emitFunctionReturn(const FunctionDecl *FD, OptPrimType ReturnType,
+                          bool CanThrow = false);
+
 protected:
   /// Variable to storage mapping.
   llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
diff --git a/clang/lib/AST/ByteCode/Context.cpp 
b/clang/lib/AST/ByteCode/Context.cpp
index 92a2ba57e08bf..afb9ce6c7eb99 100644
--- a/clang/lib/AST/ByteCode/Context.cpp
+++ b/clang/lib/AST/ByteCode/Context.cpp
@@ -33,6 +33,9 @@ Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new 
Program(*this)) {
   this->LongLongWidth = Ctx.getTargetInfo().getLongLongWidth();
   assert(Ctx.getTargetInfo().getCharWidth() == 8 &&
          "We're assuming 8 bit chars");
+
+  this->ExceptionsEnabled =
+      Ctx.getLangOpts().CPlusPlus26 && Ctx.getLangOpts().CXXExceptions;
 }
 
 Context::~Context() = default;
diff --git a/clang/lib/AST/ByteCode/Context.h b/clang/lib/AST/ByteCode/Context.h
index 47821a3e3a7f3..9b0a6976894cf 100644
--- a/clang/lib/AST/ByteCode/Context.h
+++ b/clang/lib/AST/ByteCode/Context.h
@@ -46,6 +46,8 @@ class EvalIDScope;
 /// Holds all information required to evaluate constexpr code in a module.
 class Context final {
 public:
+  unsigned ExceptionsEnabled : 1;
+
   /// Initialises the constexpr VM.
   explicit Context(ASTContext &Ctx);
 
diff --git a/clang/lib/AST/ByteCode/Disasm.cpp 
b/clang/lib/AST/ByteCode/Disasm.cpp
index 4caf830a0a1b4..419b5a4ef5ada 100644
--- a/clang/lib/AST/ByteCode/Disasm.cpp
+++ b/clang/lib/AST/ByteCode/Disasm.cpp
@@ -165,6 +165,14 @@ LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS,
   OS << "rvo:        " << hasRVO() << "\n";
   OS << "this arg:   " << hasThisPointer() << "\n";
 
+  // Print exception table.
+  if (!ExceptionTable.empty()) {
+    for (auto &EE : ExceptionTable) {
+      OS << EE.CodeStart << ".." << EE.CodeEnd << " -> " << EE.Target << " ("
+         << EE.CatchType << ")\n";
+    }
+  }
+
   struct OpText {
     size_t Addr;
     std::string Op;
diff --git a/clang/lib/AST/ByteCode/EvalEmitter.h 
b/clang/lib/AST/ByteCode/EvalEmitter.h
index f939ef4839a19..4e2bc2da5556f 100644
--- a/clang/lib/AST/ByteCode/EvalEmitter.h
+++ b/clang/lib/AST/ByteCode/EvalEmitter.h
@@ -62,6 +62,16 @@ class EvalEmitter : public SourceMapper {
 
   virtual ~EvalEmitter();
 
+  unsigned currentCodeSize() const {
+    llvm_unreachable("Should never be called on EvalEmitter");
+    return 0;
+  }
+
+  void registerExceptionHandler(unsigned From, unsigned To, unsigned Target,
+                                UnsignedOrNone, const Type *T) {
+    llvm_unreachable("Should never be called on EvalEmitter");
+  }
+
   /// Define a label.
   void emitLabel(LabelTy Label);
   /// Create a label.
diff --git a/clang/lib/AST/ByteCode/Exceptions.cpp 
b/clang/lib/AST/ByteCode/Exceptions.cpp
new file mode 100644
index 0000000000000..ad8f5476f16a0
--- /dev/null
+++ b/clang/lib/AST/ByteCode/Exceptions.cpp
@@ -0,0 +1,56 @@
+//===-------------------------- Exceptions.cpp ------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Exceptions.h"
+#include "clang/AST/ASTContext.h"
+
+using namespace clang;
+using namespace clang::interp;
+
+bool ExceptionTableEntry::canCatch(const Type *ThrowType) const {
+  const Type *CatchType = this->CatchType;
+
+  if (!CatchType || ASTContext::hasSameType(CatchType, ThrowType))
+    return true;
+
+  assert(CatchType);
+
+  // nullptr_t can be caught by any pointer type.
+  if (ThrowType->isNullPtrType() && CatchType->isPointerType())
+    return true;
+
+  // void* can catch all thown pointer types.
+  if (ThrowType->isPointerType() && CatchType->isVoidPointerType())
+    return true;
+
+  if (CatchType->isPointerType() && !ThrowType->isPointerType())
+    return false;
+
+  if (CatchType->isPointerOrReferenceType())
+    CatchType = CatchType->getPointeeType().getTypePtr();
+  if (ThrowType->isPointerOrReferenceType())
+    ThrowType = ThrowType->getPointeeType().getTypePtr();
+
+  if (CatchType == ThrowType)
+    return true;
+
+  if (CatchType->isRecordType() && ThrowType->isRecordType()) {
+    const CXXRecordDecl *CatchDecl = CatchType->getAsCXXRecordDecl();
+    const CXXRecordDecl *ThrowDecl = ThrowType->getAsCXXRecordDecl();
+    assert(CatchDecl);
+    assert(ThrowDecl);
+
+    if (CatchDecl == ThrowDecl)
+      return true;
+
+    if (ThrowDecl->isDerivedFrom(CatchDecl))
+      return true;
+  }
+
+  return false;
+}
diff --git a/clang/lib/AST/ByteCode/Exceptions.h 
b/clang/lib/AST/ByteCode/Exceptions.h
new file mode 100644
index 0000000000000..cb750b7acd0cf
--- /dev/null
+++ b/clang/lib/AST/ByteCode/Exceptions.h
@@ -0,0 +1,34 @@
+//===----------------------- Exceptions.h  ----------------------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_INTERP_EXCEPTIONS_H
+#define LLVM_CLANG_AST_INTERP_EXCEPTIONS_H
+
+#include "clang/Basic/OptionalUnsigned.h"
+
+namespace clang {
+class Type;
+
+namespace interp {
+
+struct ExceptionTableEntry {
+  unsigned CodeStart;
+  unsigned CodeEnd;
+  unsigned Target;
+  UnsignedOrNone DeclOffset;
+  /// If CatchType is nullptr, this is a catch-all handler.
+  const Type *CatchType;
+
+  /// Check if this exception table entry can catch an exception thrown of the
+  /// given type.
+  bool canCatch(const Type *ThrowType) const;
+};
+
+} // namespace interp
+} // namespace clang
+#endif
diff --git a/clang/lib/AST/ByteCode/Function.cpp 
b/clang/lib/AST/ByteCode/Function.cpp
index cd0f7eb125230..02d5c9b13fa78 100644
--- a/clang/lib/AST/ByteCode/Function.cpp
+++ b/clang/lib/AST/ByteCode/Function.cpp
@@ -69,3 +69,12 @@ SourceInfo Function::getSource(CodePtr PC) const {
     return SrcMap.back().second;
   return It->second;
 }
+
+std::optional<ExceptionTableEntry>
+Function::findCatchHandler(unsigned CodeOffset, const Type *Ty) const {
+  for (const auto &E : ExceptionTable) {
+    if (CodeOffset >= E.CodeStart && CodeOffset <= E.CodeEnd && E.canCatch(Ty))
+      return E;
+  }
+  return std::nullopt;
+}
diff --git a/clang/lib/AST/ByteCode/Function.h 
b/clang/lib/AST/ByteCode/Function.h
index 289bd64124004..f5dce4d069189 100644
--- a/clang/lib/AST/ByteCode/Function.h
+++ b/clang/lib/AST/ByteCode/Function.h
@@ -16,6 +16,7 @@
 #define LLVM_CLANG_AST_INTERP_FUNCTION_H
 
 #include "Descriptor.h"
+#include "Exceptions.h"
 #include "Source.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
@@ -250,6 +251,9 @@ class Function final {
     return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
   }
 
+  std::optional<ExceptionTableEntry> findCatchHandler(unsigned CodeOffset,
+                                                      const Type *Ty) const;
+
 private:
   /// Construct a function representing an actual function.
   Function(Program &P, FunctionDeclTy Source, unsigned ArgSize,
@@ -259,13 +263,15 @@ class Function final {
   /// Sets the code of a function.
   void setCode(FunctionDeclTy Source, unsigned NewFrameSize,
                llvm::SmallVector<std::byte> &&NewCode, SourceMap &&NewSrcMap,
-               llvm::SmallVector<Scope, 2> &&NewScopes, bool NewHasBody,
-               bool NewIsValid) {
+               llvm::SmallVector<Scope, 2> &&NewScopes,
+               llvm::SmallVector<ExceptionTableEntry> &&ExceptionTable,
+               bool NewHasBody, bool NewIsValid) {
     this->Source = Source;
     FrameSize = NewFrameSize;
     Code = std::move(NewCode);
     SrcMap = std::move(NewSrcMap);
     Scopes = std::move(NewScopes);
+    this->ExceptionTable = std::move(ExceptionTable);
     IsValid = NewIsValid;
     HasBody = NewHasBody;
   }
@@ -296,6 +302,7 @@ class Function final {
   llvm...
[truncated]

``````````

</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