Home | History | Annotate | Download | only in gsl
      1 ///////////////////////////////////////////////////////////////////////////////
      2 //
      3 // Copyright (c) 2015 Microsoft Corporation. All rights reserved.
      4 //
      5 // This code is licensed under the MIT License (MIT).
      6 //
      7 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      8 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      9 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     10 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     11 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     12 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     13 // THE SOFTWARE.
     14 //
     15 ///////////////////////////////////////////////////////////////////////////////
     16 
     17 #ifndef GSL_CONTRACTS_H
     18 #define GSL_CONTRACTS_H
     19 
     20 #include <exception>
     21 #include <stdexcept> // for logic_error
     22 
     23 //
     24 // make suppress attributes parse for some compilers
     25 // Hopefully temporary until suppression standardization occurs
     26 //
     27 #if defined(__clang__)
     28 #define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
     29 #else
     30 #if defined(_MSC_VER)
     31 #define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
     32 #else
     33 #define GSL_SUPPRESS(x)
     34 #endif // _MSC_VER
     35 #endif // __clang__
     36 
     37 //
     38 // Temporary until MSVC STL supports no-exceptions mode.
     39 // Currently terminate is a no-op in this mode, so we add termination behavior back
     40 //
     41 #if defined(_MSC_VER) && defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS
     42 #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
     43 #include <intrin.h>
     44 #define RANGE_CHECKS_FAILURE 0
     45 
     46 #if defined(__clang__)
     47 #pragma clang diagnostic push
     48 #pragma clang diagnostic ignored "-Winvalid-noreturn"
     49 #endif
     50 
     51 #endif
     52 
     53 //
     54 // There are three configuration options for this GSL implementation's behavior
     55 // when pre/post conditions on the GSL types are violated:
     56 //
     57 // 1. GSL_TERMINATE_ON_CONTRACT_VIOLATION: std::terminate will be called (default)
     58 // 2. GSL_THROW_ON_CONTRACT_VIOLATION: a gsl::fail_fast exception will be thrown
     59 // 3. GSL_UNENFORCED_ON_CONTRACT_VIOLATION: nothing happens
     60 //
     61 #if !(defined(GSL_THROW_ON_CONTRACT_VIOLATION) || defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION) ||  \
     62       defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION))
     63 #define GSL_TERMINATE_ON_CONTRACT_VIOLATION
     64 #endif
     65 
     66 #define GSL_STRINGIFY_DETAIL(x) #x
     67 #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
     68 
     69 #if defined(__clang__) || defined(__GNUC__)
     70 #define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
     71 #define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
     72 #else
     73 #define GSL_LIKELY(x) (!!(x))
     74 #define GSL_UNLIKELY(x) (!!(x))
     75 #endif
     76 
     77 //
     78 // GSL_ASSUME(cond)
     79 //
     80 // Tell the optimizer that the predicate cond must hold. It is unspecified
     81 // whether or not cond is actually evaluated.
     82 //
     83 #ifdef _MSC_VER
     84 #define GSL_ASSUME(cond) __assume(cond)
     85 #elif defined(__GNUC__)
     86 #define GSL_ASSUME(cond) ((cond) ? static_cast<void>(0) : __builtin_unreachable())
     87 #else
     88 #define GSL_ASSUME(cond) static_cast<void>((cond) ? 0 : 0)
     89 #endif
     90 
     91 //
     92 // GSL.assert: assertions
     93 //
     94 
     95 namespace gsl
     96 {
     97 struct fail_fast : public std::logic_error
     98 {
     99     explicit fail_fast(char const* const message) : std::logic_error(message) {}
    100 };
    101 
    102 namespace details
    103 {
    104 #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
    105 
    106     typedef void  (__cdecl *terminate_handler)();
    107 
    108     GSL_SUPPRESS(f.6) // NO-FORMAT: attribute
    109     [[noreturn]] inline void __cdecl default_terminate_handler()
    110     {
    111         __fastfail(RANGE_CHECKS_FAILURE);
    112     }
    113 
    114     inline gsl::details::terminate_handler& get_terminate_handler() noexcept
    115     {
    116         static terminate_handler handler = &default_terminate_handler;
    117         return handler;
    118     }
    119 
    120 #endif
    121 
    122     [[noreturn]] inline void terminate() noexcept
    123     {
    124 #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
    125         (*gsl::details::get_terminate_handler())();
    126 #else
    127         std::terminate();
    128 #endif
    129     }
    130 
    131 #if defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
    132 
    133     template <typename Exception>
    134     [[noreturn]] void throw_exception(Exception&&) noexcept
    135     {
    136         gsl::details::terminate();
    137     }
    138 
    139 #else
    140 
    141     template <typename Exception>
    142     [[noreturn]] void throw_exception(Exception&& exception)
    143     {
    144         throw std::forward<Exception>(exception);
    145     }
    146 
    147 #endif // GSL_TERMINATE_ON_CONTRACT_VIOLATION
    148 
    149 } // namespace details
    150 } // namespace gsl
    151 
    152 #if defined(GSL_THROW_ON_CONTRACT_VIOLATION)
    153 
    154 #define GSL_CONTRACT_CHECK(type, cond)                                                             \
    155     (GSL_LIKELY(cond) ? static_cast<void>(0)                                                       \
    156                       : gsl::details::throw_exception(gsl::fail_fast(                              \
    157                             "GSL: " type " failure at " __FILE__ ": " GSL_STRINGIFY(__LINE__))))
    158 
    159 #elif defined(GSL_TERMINATE_ON_CONTRACT_VIOLATION)
    160 
    161 #define GSL_CONTRACT_CHECK(type, cond)                                                             \
    162     (GSL_LIKELY(cond) ? static_cast<void>(0) : gsl::details::terminate())
    163 
    164 #elif defined(GSL_UNENFORCED_ON_CONTRACT_VIOLATION)
    165 
    166 #define GSL_CONTRACT_CHECK(type, cond) GSL_ASSUME(cond)
    167 
    168 #endif // GSL_THROW_ON_CONTRACT_VIOLATION
    169 
    170 #define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
    171 #define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
    172 
    173 #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__)
    174 #pragma clang diagnostic pop
    175 #endif
    176 
    177 #endif // GSL_CONTRACTS_H
    178