FLANG

idioms.h
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 "llvm/Support/Compiler.h"
27 #include <functional>
28 #include <list>
29 #include <optional>
30 #include <string>
31 #include <tuple>
32 #include <type_traits>
33 #include <variant>
34
35 #if __GNUC__ == 7
36 // Avoid a deduction bug in GNU 7.x headers by forcing the answer.
37 namespace std {
38 template <typename A>
39 struct is_trivially_copy_constructible<list<A>> : false_type {};
40 template <typename A>
41 struct is_trivially_copy_constructible<optional<list<A>>> : false_type {};
42 } // namespace std
43 #endif
44
45 // enable "this is a std::string"s with the 's' suffix
46 using namespace std::literals::string_literals;
47
48 namespace Fortran::common {
49
50 // Helper templates for combining a list of lambdas into an anonymous
51 // struct for use with std::visit() on a std::variant<> sum type.
52 // E.g.: std::visit(visitors{
53 // [&](const firstType &x) { ... },
54 // [&](const secondType &x) { ... },
55 // ...
56 // [&](const auto &catchAll) { ... }}, variantObject);
57
58 template <typename... LAMBDAS> struct visitors : LAMBDAS... {
59 using LAMBDAS::operator()...;
60 };
61
62 template <typename... LAMBDAS> visitors(LAMBDAS... x) -> visitors<LAMBDAS...>;
63
64 // Calls std::fprintf(stderr, ...), then abort().
65 [[noreturn]] void die(const char *, ...);
66
67 #define DIE(x) Fortran::common::die(x " at " __FILE__ "(%d)", __LINE__)
68
69 // For switch statement default: labels.
70 #define CRASH_NO_CASE DIE("no case")
71
72 // clang-format off
73 // For switch statements whose cases have return statements for
74 // all possibilities. Clang emits warnings if the default: is
75 // present, gcc emits warnings if it is absent.
76 #if __clang__
77 #define SWITCH_COVERS_ALL_CASES
78 #else
79 #define SWITCH_COVERS_ALL_CASES default: CRASH_NO_CASE;
80 #endif
81 // clang-format on
82
83 // For cheap assertions that should be applied in production.
84 // To disable, compile with '-DCHECK=(void)'
85 #ifndef CHECK
86 #define CHECK(x) ((x) || (DIE("CHECK(" #x ") failed"), false))
87 #endif
88
89 // User-defined type traits that default to false:
90 // Invoke CLASS_TRAIT(traitName) to define a trait, then put
91 // using traitName = std::true_type; (or false_type)
92 // into the appropriate class definitions. You can then use
93 // typename std::enable_if_t<traitName<...>, ...>
94 // in template specialization definitions.
95 #define CLASS_TRAIT(T) \
96 namespace class_trait_ns_##T { \
97 template <typename A> std::true_type test(typename A::T *); \
98 template <typename A> std::false_type test(...); \
99 template <typename A> \
100 constexpr bool has_trait{decltype(test<A>(nullptr))::value}; \
101 template <typename A> constexpr bool trait_value() { \
102 if constexpr (has_trait<A>) { \
103 using U = typename A::T; \
104 return U::value; \
105 } else { \
106 return false; \
107 } \
108 } \
109 } \
110 template <typename A> constexpr bool T{class_trait_ns_##T::trait_value<A>()};
111
112 // Define enum class NAME with the given enumerators, a static
113 // function EnumToString() that maps enumerators to std::string,
114 // and a constant NAME_enumSize that captures the number of items
115 // in the enum class.
116
117 std::string EnumIndexToString(int index, const char *names);
118
119 template <typename A> struct ListItemCount {
120 constexpr ListItemCount(std::initializer_list<A> list) : value{list.size()} {}
121 const std::size_t value;
122 };
123
124 #define ENUM_CLASS(NAME, ...) \
125 enum class NAME { __VA_ARGS__ }; \
126 LLVM_ATTRIBUTE_UNUSED static constexpr std::size_t NAME##_enumSize{[] { \
127 enum { __VA_ARGS__ }; \
128 return Fortran::common::ListItemCount{__VA_ARGS__}.value; \
129 }()}; \
130 LLVM_ATTRIBUTE_UNUSED static inline std::string EnumToString(NAME e) { \
131 return Fortran::common::EnumIndexToString( \
132 static_cast<int>(e), #__VA_ARGS__); \
133 }
134
135 // Check that a pointer is non-null and dereference it
136 #define DEREF(p) Fortran::common::Deref(p, __FILE__, __LINE__)
137
138 template <typename T> constexpr T &Deref(T *p, const char *file, int line) {
139 if (!p) {
140 Fortran::common::die("nullptr dereference at %s(%d)", file, line);
141 }
142 return *p;
143 }
144
145 // Given a const reference to a value, return a copy of the value.
146 template <typename A> A Clone(const A &x) { return x; }
147
148 // C++ does a weird and dangerous thing when deducing template type parameters
149 // from function arguments: lvalue references are allowed to match rvalue
150 // reference arguments. Template function declarations like
151 // template<typename A> int foo(A &&);
152 // need to be protected against this C++ language feature when functions
153 // may modify such arguments. Use these type functions to invoke SFINAE
154 // on a result type via
155 // template<typename A> common::IfNoLvalue<int, A> foo(A &&);
156 // or, for constructors,
157 // template<typename A, typename = common::NoLvalue<A>> int foo(A &&);
158 // This works with parameter packs too.
159 template <typename A, typename... B>
160 using IfNoLvalue = std::enable_if_t<(... && !std::is_lvalue_reference_v<B>), A>;
161 template <typename... RVREF> using NoLvalue = IfNoLvalue<void, RVREF...>;
162 } // namespace Fortran::common
163 #endif // FORTRAN_COMMON_IDIOMS_H_
Fortran::common::ListItemCount
Definition: idioms.h:119
Fortran::common::visitors
Definition: idioms.h:58