================
@@ -1596,3 +1599,422 @@ case will be handled by the personality function, using
tables that are
generated from the `cir.catchpad` operations. Each catch handler simply
continues to the normal continuation block (`^bb6`) using the
`cir.catchret` operation.
+
+## Dynamic Exception Specifications
+
+A dynamic exception specification (`throw(T...)`, and `throw()` before
+C++17) constrains the set of exception types that a function is allowed
+to propagate to its caller. If an exception of any other type would
+escape the function, `std::unexpected()` must be called instead
+([except.spec]). Dynamic exception specifications were removed in C++17,
+so this representation is only produced for earlier language modes.
+Functions declared `noexcept`, and `throw()` in C++17 and later, are handled
+differently.
+
+Because the constraint applies to every exception that could escape the
+function, it is represented as an exception handler that encloses the
+entire function body. This section describes that representation used by the
+high-level CIR produced by CIR generation, the flattened form produced by
`cir::FlattenCFG`, and the ABI-specific form produced by EH ABI lowering.
+
+### High-level CIR representation
+
+A function with a dynamic exception specification has its entire body
+wrapped in a `cir.try` operation whose handler is a *filter* handler.
+A filter handler is identified by a `#cir.eh_filter` handler type
+attribute, which carries the list of type info symbols naming the
+permitted types.
+
+```mlir
+cir.try {
+ // function body
+ cir.yield
+} filter [@_ZTIi] (%eh_token : !cir.eh_token) {
+ cir.resume %eh_token : !cir.eh_token
+}
+```
+
+The `#cir.eh_filter` attribute occupies a slot in the try operation's
+handler type list, in the same way that a `#cir.global_view` catch type,
+`catch all`, or `unwind` does. Like `unwind`, and unlike a catch
+handler, a filter handler region does not begin with `cir.begin_catch`.
+A filter does not catch the exception. It only decides whether the
+exception is permitted to continue unwinding.
+
+The test that decides whether the in-flight exception matches the filter
+is implicit in the handler type, in the same way that the type test for
+a catch handler is implicit in its `#cir.global_view` handler type.
+Neither test is expressed in the handler region. Both are materialized
+during CFG flattening and ABI lowering. The body of a filter handler
+region therefore contains only the code that runs when the exception
+*is* permitted by the specification, which is a single `cir.resume`
+operation to continue unwinding to the caller.
+
+A `cir.try` operation may have at most one filter handler, it must be
+the last handler in the handler list, and it may not be combined with a
----------------
andykaylor wrote:
Good question. It's "last" because it's effectively a catch-all, but it will
also be "only" in the way that I intend to generate it. The claim that it will
be "last" is anticipating cases where we might decide to fold the outer try
operation with a directly enclosed inner try op. For instance:
```
cir.try {
cir.scope {
cir.try {
...
} catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>]
(%eh_token : !cir.eh_token) {
...
} unwind (%eh_token.1 : !cir.eh_token) {
cir.resume %eh_token.1 : !cir.eh_token
}
}
cir.yield
} filter [] (%eh_token.2 : !cir.eh_token) {
cir.unreachable
}
```
Could, in theory, become:
```
cir.try {
...
} catch [type #cir.global_view<@_ZTIi> : !cir.ptr<!u8i>]
(%eh_token : !cir.eh_token) {
...
} filter [] (%eh_token.2 : !cir.eh_token) {
cir.unreachable
}
```
But I'm not sure there's any benefit to that, and we'd need to prevent such
folding in any number of cases, not least of which is the case where the
enclosed try op has a catch-all clause. So maybe it's better to just say that
if the try op has a filter that must be the only handler.
https://github.com/llvm/llvm-project/pull/222451
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits