/* * Copyright 2018-present Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include namespace folly { /// throw_exception /// /// Throw an exception if exceptions are enabled, or terminate if compiled with /// -fno-exceptions. template [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception(Ex&& ex) { #if FOLLY_HAS_EXCEPTIONS throw static_cast(ex); #else (void)ex; std::terminate(); #endif } /// terminate_with /// /// Terminates as if by forwarding to throw_exception but in a noexcept context. template [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void terminate_with(Ex&& ex) noexcept { throw_exception(static_cast(ex)); } // clang-format off namespace detail { template FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN T&& to_exception_arg_(T&& t) { return static_cast(t); } template FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN char const* to_exception_arg_( char const (&array)[N]) { return static_cast(array); } template [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void throw_exception_(Args&&... args) { throw_exception(Ex(static_cast(args)...)); } template [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void terminate_with_( Args&&... args) noexcept { throw_exception(Ex(static_cast(args)...)); } } // namespace detail // clang-format on /// throw_exception /// /// Construct and throw an exception if exceptions are enabled, or terminate if /// compiled with -fno-exceptions. /// /// Converts any arguments of type `char const[N]` to `char const*`. template [[noreturn]] FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN void throw_exception(Args&&... args) { detail::throw_exception_( detail::to_exception_arg_(static_cast(args))...); } /// terminate_with /// /// Terminates as if by forwarding to throw_exception but in a noexcept context. // clang-format off template [[noreturn]] FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN void terminate_with(Args&&... args) noexcept { detail::terminate_with_( detail::to_exception_arg_(static_cast(args))...); } // clang-format on /// invoke_noreturn_cold /// /// Invoke the provided function with the provided arguments. If the invocation /// returns, terminate. /// /// May be used with throw_exception in cases where construction of the object /// to be thrown requires more than just invoking its constructor with a given /// sequence of arguments passed by reference - for example, if a string message /// must be computed before being passed to the constructor of the object to be /// thrown. /// /// Usage note: /// Passing extra values as arguments rather than capturing them allows smaller /// bytecode at the call-site. /// /// Example: /// /// if (i < 0) { /// invoke_noreturn_cold( /// [](int j) { /// throw_exceptions(runtime_error(to("invalid: ", j))); /// }, /// i); /// } template [[noreturn]] FOLLY_NOINLINE FOLLY_COLD void invoke_noreturn_cold( F&& f, A&&... a) { static_cast(f)(static_cast(a)...); std::terminate(); } } // namespace folly