Warning: This file is not a C or C++ file. It does not have highlighting.
1 | //===-- include/flang/Common/idioms.h ---------------------------*- C++ -*-===// |
---|---|
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #ifndef FORTRAN_COMMON_IDIOMS_H_ |
10 | #define FORTRAN_COMMON_IDIOMS_H_ |
11 | |
12 | // Defines anything that might ever be useful in more than one source file |
13 | // or that is too weird or too specific to the host C++ compiler to be |
14 | // exposed elsewhere. |
15 | |
16 | #ifndef __cplusplus |
17 | #error this is a C++ program |
18 | #endif |
19 | #if __cplusplus < 201703L |
20 | #error this is a C++17 program |
21 | #endif |
22 | #if !__clang__ && defined __GNUC__ && __GNUC__ < 7 |
23 | #error g++ >= 7.2 is required |
24 | #endif |
25 | |
26 | #include "enum-class.h" |
27 | #include "variant.h" |
28 | #include "visit.h" |
29 | #include <array> |
30 | #include <functional> |
31 | #include <list> |
32 | #include <memory> |
33 | #include <optional> |
34 | #include <string> |
35 | #include <tuple> |
36 | #include <type_traits> |
37 | |
38 | #if __GNUC__ == 7 |
39 | // Avoid a deduction bug in GNU 7.x headers by forcing the answer. |
40 | namespace std { |
41 | template <typename A> |
42 | struct is_trivially_copy_constructible<list<A>> : false_type {}; |
43 | template <typename A> |
44 | struct is_trivially_copy_constructible<optional<list<A>>> : false_type {}; |
45 | } // namespace std |
46 | #endif |
47 | |
48 | // enable "this is a std::string"s with the 's' suffix |
49 | using namespace std::literals::string_literals; |
50 | |
51 | namespace Fortran::common { |
52 | |
53 | // Helper templates for combining a list of lambdas into an anonymous |
54 | // struct for use with common::visit() on a std::variant<> sum type. |
55 | // E.g.: common::visit(visitors{ |
56 | // [&](const firstType &x) { ... }, |
57 | // [&](const secondType &x) { ... }, |
58 | // ... |
59 | // [&](const auto &catchAll) { ... }}, variantObject); |
60 | |
61 | template <typename... LAMBDAS> struct visitors : LAMBDAS... { |
62 | using LAMBDAS::operator()...; |
63 | }; |
64 | |
65 | template <typename... LAMBDAS> visitors(LAMBDAS... x) -> visitors<LAMBDAS...>; |
66 | |
67 | // Calls std::fprintf(stderr, ...), then abort(). |
68 | [[noreturn]] void die(const char *, ...); |
69 | |
70 | #define DIE(x) Fortran::common::die(x " at " __FILE__ "(%d)", __LINE__) |
71 | |
72 | // For switch statement default: labels. |
73 | #define CRASH_NO_CASE DIE("no case") |
74 | |
75 | // clang-format off |
76 | // For switch statements whose cases have return statements for |
77 | // all possibilities. Clang emits warnings if the default: is |
78 | // present, gcc emits warnings if it is absent. |
79 | #if __clang__ |
80 | #define SWITCH_COVERS_ALL_CASES |
81 | #else |
82 | #define SWITCH_COVERS_ALL_CASES default: CRASH_NO_CASE; |
83 | #endif |
84 | // clang-format on |
85 | |
86 | // For cheap assertions that should be applied in production. |
87 | // To disable, compile with '-DCHECK=(void)' |
88 | #ifndef CHECK |
89 | #define CHECK(x) ((x) || (DIE("CHECK(" #x ") failed"), false)) |
90 | // Same as above, but with a custom error message. |
91 | #define CHECK_MSG(x, y) ((x) || (DIE("CHECK(" #x ") failed: " #y), false)) |
92 | #endif |
93 | |
94 | // User-defined type traits that default to false: |
95 | // Invoke CLASS_TRAIT(traitName) to define a trait, then put |
96 | // using traitName = std::true_type; (or false_type) |
97 | // into the appropriate class definitions. You can then use |
98 | // typename std::enable_if_t<traitName<...>, ...> |
99 | // in template specialization definitions. |
100 | #define CLASS_TRAIT(T) \ |
101 | namespace class_trait_ns_##T { \ |
102 | template <typename A> std::true_type test(typename A::T *); \ |
103 | template <typename A> std::false_type test(...); \ |
104 | template <typename A> \ |
105 | constexpr bool has_trait{decltype(test<A>(nullptr))::value}; \ |
106 | template <typename A> constexpr bool trait_value() { \ |
107 | if constexpr (has_trait<A>) { \ |
108 | using U = typename A::T; \ |
109 | return U::value; \ |
110 | } else { \ |
111 | return false; \ |
112 | } \ |
113 | } \ |
114 | } \ |
115 | template <typename A> constexpr bool T{class_trait_ns_##T::trait_value<A>()}; |
116 | |
117 | // Check that a pointer is non-null and dereference it |
118 | #define DEREF(p) Fortran::common::Deref(p, __FILE__, __LINE__) |
119 | |
120 | template <typename T> constexpr T &Deref(T *p, const char *file, int line) { |
121 | if (!p) { |
122 | Fortran::common::die("nullptr dereference at %s(%d)", file, line); |
123 | } |
124 | return *p; |
125 | } |
126 | |
127 | template <typename T> |
128 | constexpr T &Deref(const std::unique_ptr<T> &p, const char *file, int line) { |
129 | if (!p) { |
130 | Fortran::common::die("nullptr dereference at %s(%d)", file, line); |
131 | } |
132 | return *p; |
133 | } |
134 | |
135 | // Given a const reference to a value, return a copy of the value. |
136 | template <typename A> A Clone(const A &x) { return x; } |
137 | |
138 | // C++ does a weird and dangerous thing when deducing template type parameters |
139 | // from function arguments: lvalue references are allowed to match rvalue |
140 | // reference arguments. Template function declarations like |
141 | // template<typename A> int foo(A &&); |
142 | // need to be protected against this C++ language feature when functions |
143 | // may modify such arguments. Use these type functions to invoke SFINAE |
144 | // on a result type via |
145 | // template<typename A> common::IfNoLvalue<int, A> foo(A &&); |
146 | // or, for constructors, |
147 | // template<typename A, typename = common::NoLvalue<A>> int foo(A &&); |
148 | // This works with parameter packs too. |
149 | template <typename A, typename... B> |
150 | using IfNoLvalue = std::enable_if_t<(... && !std::is_lvalue_reference_v<B>), A>; |
151 | template <typename... RVREF> using NoLvalue = IfNoLvalue<void, RVREF...>; |
152 | } // namespace Fortran::common |
153 | #endif // FORTRAN_COMMON_IDIOMS_H_ |
154 |
Warning: This file is not a C or C++ file. It does not have highlighting.