Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
contract.hpp
Go to the documentation of this file.
1// Copyright 2024, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_CONTRACTS_CONTRACT_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_CONTRACTS_CONTRACT_HPP_
7
8// IWYU pragma: private, include "arene/base/contracts.hpp"
9// IWYU pragma: friend "(arene/base(?!/tests)|stdlib/include/stdlib_detail)/.*"
10
11// parasoft-begin-suppress AUTOSAR-A16_2_2-a-2 "Arene Base aggregate headers permitted by A16-2-2 Permit #1"
12#include "arene/base/compiler_support/attributes.hpp"
13#include "arene/base/compiler_support/expect.hpp"
14#include "arene/base/compiler_support/preprocessor.hpp"
15#include "arene/base/detail/raw_c_string.hpp"
16#include "arene/base/stdlib_choice/cstdint.hpp"
17// parasoft-end-suppress AUTOSAR-A16_2_2-a-2
18
19// AUTOSAR exceptions:
20// A16-0-1 The pre-processor shall only be used for unconditional and
21// conditional file inclusion and include guards, and using the following
22// directives: (1) #ifndef, (2) #ifdef, (3) #if, (4) #if defined, (5) #elif, (6)
23// #else, (7) #define, (8) #endif, (9) #include.
24//
25// Exception Rationale: The code below is used to make precondition and
26// invariant checks in a way that can be used by everyone, which can thus be
27// used to improve safety. The ARENE_DOC_GENERATION_RUNNING macro is also used
28// to identify when Doxygen is running and present different definitions to
29// Doxygen vs the compiler, in order to give improved documentation.
30
31// NOLINTBEGIN(cppcoreguidelines-macro-usage)
32// parasoft-begin-suppress AUTOSAR-A16_0_1-d-2 "Use of function-like macros permitted by A16-0-1 Permit #1"
33// parasoft-begin-suppress AUTOSAR-A16_0_1-a-2 "Conditional defines permitted by A16-0-1 Permit #2"
34
35namespace arene {
36namespace base {
37namespace contract_detail {
38
39/// @brief The type of contract being checked
40// parasoft-begin-suppress AUTOSAR-A2_7_3 "False positive: documented"
41enum class contract_type : std::uint8_t {
42 precondition, ///< The contract violation is from @c ARENE_PRECONDITION
43 invariant, ///< The contract violation is from @c ARENE_INVARIANT
44 unreachable ///< The contract violation is from @c ARENE_INVARIANT_UNREACHABLE
45};
46// parasoft-end-suppress AUTOSAR-A2_7_3
47
48/// @brief A structure holding information about a contract violation
49// parasoft-begin-suppress AUTOSAR-A2_7_3 "False positive: documented"
50struct contract_violation_info {
51 /// @brief The filename of the violation location
52 detail::raw_c_string file;
53 /// @brief The line number of the violation location as a string
54 detail::raw_c_string line;
55 /// @brief The text form of the message about the violation
56 detail::raw_c_string message;
57 /// @brief The type of contract
58 contract_type type;
59};
60// parasoft-end-suppress AUTOSAR-A2_7_3
61
62/// @brief Class to create static storage duration values for the contract violation info
63/// @tparam Factory A class with a @c arene_contract_make_info function to obtain the violation info
64// parasoft-begin-suppress AUTOSAR-A2_7_3 "False positive: documented"
65template <typename Factory>
66struct info_holder {
67 // parasoft-begin-suppress AUTOSAR-M8_5_2-c-2 "False positive: whole value is copied, with brace initialization"
68 /// @brief The contract violation info
69 static constexpr contract_violation_info value{Factory::arene_contract_make_info()};
70 // parasoft-end-suppress AUTOSAR-M8_5_2-c-2
71};
72// parasoft-end-suppress AUTOSAR-A2_7_3
73
74template <typename Factory>
75constexpr contract_violation_info info_holder<Factory>::value;
76
77/// @brief Internal function called when a contract is violated. It outputs the details on standard error and terminates
78/// the application.
79/// @param info Information about the contract
80// parasoft-begin-suppress AUTOSAR-A2_7_3 "False positive: documented"
81ARENE_NORETURN void contract_violation(contract_violation_info const& info) noexcept;
82// parasoft-end-suppress AUTOSAR-A2_7_3
83
84/// @brief Wrapper around contract_violation() to allow contracts to be constexpr-compatible on the success path without
85/// brining platform-specific implementation details into the header.
86/// @param info Information about the violated contract
87// parasoft-begin-suppress AUTOSAR-A2_7_3 "False positive: documented"
88ARENE_NORETURN constexpr void contract_violation_wrapper(contract_violation_info const& info) noexcept {
89 // This do-while loop ensures that this function never returns, to satisfy the ARENE_NORETURN annotation
90 // It does, however, eventually invoke contract_violation due to the mutually exclusive ifs
91 do { // NOLINT(cppcoreguidelines-avoid-do-while)
92 // dummy condition to make invoking non-constexpr contract_violation() a dependent branch, otherwise compilers will
93 // consider it a non-constant-expression.
94 if (info.file != info.line) {
95 contract_violation(info);
96 }
97 if (info.file == info.line) {
98 contract_violation(info);
99 }
100 } while (true);
101}
102// parasoft-end-suppress AUTOSAR-A2_7_3
103
104} // namespace contract_detail
105} // namespace base
106} // namespace arene
107
108// parasoft-begin-suppress AUTOSAR-M16_0_6-a-2 "violation_type is the name of an enumeration member; enclosing in
109// parentheses would be invalid syntax"
110/// Call the contract violation handler for a violated contract.
111/// @param violation_type The type of contract violated
112/// @param message The violation message
113#define ARENE_INTERNAL_CONTRACT_VIOLATION(violation_type, message)
114 /*! @brief A class to provide information about the contract violation */
115 class arene_contract_info_wrapper {
116 public:
117 /*! @brief Return information about the contract violation */
118 static constexpr auto arene_contract_make_info() noexcept
119 -> ::arene::base::contract_detail::contract_violation_info {
120 return {
121 static_cast<::arene::base::detail::raw_c_string>(__FILE__),
122 static_cast<::arene::base::detail::raw_c_string>(ARENE_STRINGIZE(__LINE__)),
123 static_cast<::arene::base::detail::raw_c_string>(message),
124 ::arene::base::contract_detail::contract_type::violation_type
125 };
126 }
127 };
128 ::arene::base::contract_detail::contract_violation_wrapper(
129 ::arene::base::contract_detail::info_holder<arene_contract_info_wrapper>::value
130 )
131
132/// @brief Check if a contract condition is @c true and call the violation handler if not
133/// @param violation_type The type of contract being checked
134/// @param message The message to report if the condition is not @c true
135/// @param condition The condition to check
136#define ARENE_INTERNAL_CONTRACT_CHECK(violation_type, message, condition) /*NOLINT*/
137 do { /* NOLINT(cppcoreguidelines-avoid-do-while) */
138 if (ARENE_EXPECT((condition))) {
139 } else {
140 ARENE_INTERNAL_CONTRACT_VIOLATION(violation_type, (message));
141 }
142 } while (false)
143// parasoft-end-suppress AUTOSAR-M16_0_6-a-2
144
145/// @brief Check that a precondition holds, and terminate the application if it does not.
146/// @param condition The macro arguments must be a single expression that can be
147/// contextually converted to @c bool. The precondition holds if the expression
148/// evaluates to @c true.
149#ifdef ARENE_DOC_GENERATION_RUNNING
150#define ARENE_PRECONDITION(condition)
151#else
152#define ARENE_PRECONDITION(...) ARENE_INTERNAL_CONTRACT_CHECK(precondition, #__VA_ARGS__, (__VA_ARGS__))
153#endif
154
155/// @brief Check that an invariant holds, and terminate the application if it does not.
156/// @param condition The macro arguments must be a single expression that can be
157/// contextually converted to @c bool. The invariant holds if the expression
158/// evaluates to @c true.
159#ifdef ARENE_DOC_GENERATION_RUNNING
160
161#define ARENE_INVARIANT(condition)
162#else
163#define ARENE_INVARIANT(...) ARENE_INTERNAL_CONTRACT_CHECK(invariant, #__VA_ARGS__, (__VA_ARGS__))
164#endif
165
166/// @brief Terminate the application if this line is ever executed. The supplied message will be output in that case.
167/// @param message The message to output
168#ifdef ARENE_DOC_GENERATION_RUNNING
169
170#define ARENE_INVARIANT_UNREACHABLE(message)
171#else
172#define ARENE_INVARIANT_UNREACHABLE(message)
173 do { /* NOLINT(cppcoreguidelines-avoid-do-while) */
174 ARENE_INTERNAL_CONTRACT_VIOLATION(unreachable, (message));
175 } while (false)
176
177#endif
178
179// NOLINTEND(cppcoreguidelines-macro-usage)
180// parasoft-end-suppress AUTOSAR-A16_0_1-d-2
181// parasoft-end-suppress AUTOSAR-A16_0_1-a-2
182
183#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_CONTRACTS_CONTRACT_HPP_
#define ARENE_INTERNAL_CONTRACT_VIOLATION(violation_type, message)
Definition contract.hpp:113
#define ARENE_INTERNAL_CONTRACT_CHECK(violation_type, message, condition)
Check if a contract condition is true and call the violation handler if not.
Definition contract.hpp:136
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10