GCC Code Coverage Report


Directory: include/spy/
File: include/spy/compiler.hpp
Date: 2026-10-08 16:24:54
Exec Total Coverage
Lines: 2 2 100.0%
Functions: 1 1 100.0%
Branches: 0 0 -%

Line Branch Exec Source
1 //==================================================================================================
2 /*
3 SPY - C++ Informations Broker
4 Copyright : SPY Project Contributors
5 SPDX-License-Identifier: BSL-1.0
6 */
7 //==================================================================================================
8 #pragma once
9
10 #include <spy/detail.hpp>
11
12 #include <compare>
13
14 #if defined __has_include
15 #if __has_include(<emscripten/version.h>)
16 #include <emscripten/version.h>
17 #endif
18 #endif
19
20 namespace spy::_
21 {
22 enum class compilers
23 {
24 undefined_ = -1,
25 msvc_,
26 intel_,
27 clang_,
28 gcc_,
29 emscripten_,
30 dpcpp_,
31 nvcc_,
32 clangcl_,
33 mingw32_,
34 mingw64_
35 };
36
37 template<compilers Compiler, int M, int N, int P> struct compilers_info
38 {
39 static constexpr compilers vendor = Compiler;
40 static constexpr version_id<M, N, P> version = {};
41
42 inline constexpr explicit operator bool() const noexcept;
43
44 template<compilers C2>
45 constexpr bool operator==(compilers_info<C2, -1, 0, 0> const&) const noexcept
46 {
47 return C2 == vendor;
48 }
49
50 template<compilers C2, int M2, int N2, int P2>
51 constexpr bool operator==(compilers_info<C2, M2, N2, P2> const& c2) const noexcept
52 {
53 return C2 == vendor && version == c2.version;
54 }
55
56 template<compilers C2, int M2, int N2, int P2>
57 constexpr std::partial_ordering
58 operator<=>(compilers_info<C2, M2, N2, P2> const& c2) const noexcept
59 {
60 if constexpr(vendor == C2) return version <=> c2.version;
61 else return std::partial_ordering::unordered;
62 }
63 };
64
65 template<_::stream OS, compilers C, int M, int N, int P>
66 1 auto& operator<<(OS& os, compilers_info<C, M, N, P> const& c)
67 {
68 if(C == compilers::nvcc_) return os << "NVIDIA CUDA Compiler " << c.version;
69 if(C == compilers::msvc_) return os << "Microsoft Visual Studio " << c.version;
70 if(C == compilers::intel_) return os << "Intel(R) C++ Compiler " << c.version;
71 if(C == compilers::dpcpp_) return os << "Intel(R) oneAPI DPC++/C++ Compiler " << c.version;
72 if(C == compilers::clang_) return os << "clang " << c.version;
73 1 if(C == compilers::gcc_) return os << "g++ " << c.version;
74 if(C == compilers::emscripten_) return os << "Emscripten " << c.version;
75 if(C == compilers::clangcl_) return os << "Clang with MSVC-like command-line" << c.version;
76 if(C == compilers::mingw32_) return os << "MINGW32 g++ " << c.version;
77 if(C == compilers::mingw64_) return os << "MINGW64 g++ " << c.version;
78
79 return os << "Undefined " << c.version;
80 }
81
82 template<int M, int N, int P> using msvc_t = compilers_info<compilers::msvc_, M, N, P>;
83 template<int M, int N, int P> using intel_t = compilers_info<compilers::intel_, M, N, P>;
84 template<int M, int N, int P> using dpcpp_t = compilers_info<compilers::dpcpp_, M, N, P>;
85 template<int M, int N, int P> using nvcc_t = compilers_info<compilers::nvcc_, M, N, P>;
86 template<int M, int N, int P> using clang_t = compilers_info<compilers::clang_, M, N, P>;
87 template<int M, int N, int P> using gcc_t = compilers_info<compilers::gcc_, M, N, P>;
88 template<int M, int N, int P> using clangcl_t = compilers_info<compilers::clangcl_, M, N, P>;
89 template<int M, int N, int P> using mingw32_t = compilers_info<compilers::mingw32_, M, N, P>;
90 template<int M, int N, int P> using mingw64_t = compilers_info<compilers::mingw64_, M, N, P>;
91 template<int M, int N, int P>
92 using emscripten_t = compilers_info<compilers::emscripten_, M, N, P>;
93 }
94
95 namespace spy
96 {
97 //================================================================================================
98 // Compiler detection object type
99 //================================================================================================
100 #if defined(__NVCC__)
101 #define SPY_COMPILER_IS_NVCC
102 using compiler_type = _::nvcc_t<__CUDACC_VER_MAJOR__, __CUDACC_VER_MINOR__, 0>;
103 #elif defined(_MSC_VER) && !defined(__clang__)
104 #define SPY_COMPILER_IS_MSVC
105 using compiler_type = _::msvc_t<_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 100000>;
106 #elif defined(__MINGW32__) && !defined(__MINGW64__)
107 #define SPY_COMPILER_IS_MINGW32
108 using compiler_type = _::mingw32_t<__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__>;
109 #elif defined(__MINGW32__) && defined(__MINGW64__)
110 #define SPY_COMPILER_IS_MINGW64
111 using compiler_type = _::mingw64_t<__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__>;
112 #elif defined(_MSC_VER) && defined(__clang__)
113 #define SPY_COMPILER_IS_CLANGCL
114 using compiler_type = _::clangcl_t<__clang_major__, __clang_minor__, __clang_patchlevel__>;
115 #elif defined(__INTEL_LLVM_COMPILER)
116 #define SPY_COMPILER_IS_INTEL_DPCPP
117 #define SPY0 __INTEL_LLVM_COMPILER
118 using compiler_type = _::dpcpp_t<SPY0 / 10000, (SPY0 / 100) % 100, SPY0 % 100>;
119 #undef SPY0
120 #elif defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)
121 #define SPY_COMPILER_IS_INTEL
122 #define SPY0 __INTEL_COMPILER
123 using compiler_type = _::intel_t<(SPY0 / 100) % 100, SPY0 % 100, __INTEL_COMPILER_UPDATE>;
124 #undef SPY0
125 #elif defined(__EMSCRIPTEN__)
126 #define SPY_COMPILER_IS_CLANG
127 // Emscripten 5 renamed these and marked the lower-case spelling deprecated, which -Werror turns
128 // into a build failure. 4.x knows only the lower-case one, so both spellings stay supported.
129 #if defined(__EMSCRIPTEN_MAJOR__)
130 using compiler_type =
131 _::emscripten_t<__EMSCRIPTEN_MAJOR__, __EMSCRIPTEN_MINOR__, __EMSCRIPTEN_TINY__>;
132 #else
133 using compiler_type =
134 _::emscripten_t<__EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__>;
135 #endif
136 #undef SPY0
137 #elif defined(__clang__)
138 #define SPY_COMPILER_IS_CLANG
139 using compiler_type = _::clang_t<__clang_major__, __clang_minor__, __clang_patchlevel__>;
140 #elif defined(__GNUC__)
141 #define SPY_COMPILER_IS_GCC
142 using compiler_type = _::gcc_t<__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__>;
143 #else
144 #define SPY_COMPILER_IS_UNKNOWN
145 using compiler_type = _::compilers_info<compilers::undefined_, -1, 0, 0>;
146 #endif
147
148 //================================================================================================
149 //! @ingroup spy_compiler
150 //! @brief Compiler reporting value
151 //!
152 //! The `spy::compiler` object can be compared to any other compiler related value to verify
153 //! if the code being compiled with a specific compiler.
154 //!
155 //! Any compiler related value can be checked for equality or ordering for a given version. The
156 //! targeted version is then specified using a compiler-dependent literal.
157 //!
158 //! Additionally, any of the compiler related value are convertible to `bool`. They evaluates to
159 //! `true` if they matches the correct compiler currently used.
160 //!
161 //! @groupheader{Supported Value}
162 //!
163 //! Name | Compiler
164 //! ------------------- | -------------
165 //! `spy::clang_` | Clang
166 //! `spy::clangcl_` | Clang-CL, Clang driving the Microsoft toolchain
167 //! `spy::dpcpp_` | Intel DPC++/ICPX
168 //! `spy::emscripten_` | Emscripten
169 //! `spy::gcc_` | G++
170 //! `spy::intel_` | Intel ICC
171 //! `spy::mingw32_` | MINGW32
172 //! `spy::mingw64_` | MINGW64
173 //! `spy::msvc_` | Microsoft Visual Studio
174 //! `spy::nvcc_` | NVIDIA NVCC
175 //!
176 //! Clang-CL, MINGW32 and MINGW64 each report as themselves. Under MINGW,
177 //! `spy::compiler == spy::gcc_` is false; under Clang-CL, `spy::compiler == spy::msvc_` is false.
178 //!
179 //! @groupheader{Example}
180 //! @godbolt{samples/compiler.cpp}
181 //================================================================================================
182 constexpr inline compiler_type compiler;
183 }
184
185 namespace spy::_
186 {
187 template<compilers C, int M, int N, int P>
188 inline constexpr compilers_info<C, M, N, P>::operator bool() const noexcept
189 {
190 return spy::compiler == *this;
191 }
192 }
193
194 namespace spy
195 {
196 //================================================================================================
197 // Compilers detector stand-alone instances
198 //================================================================================================
199 constexpr inline auto nvcc_ = _::nvcc_t<-1, 0, 0> {};
200 constexpr inline auto msvc_ = _::msvc_t<-1, 0, 0> {};
201 constexpr inline auto intel_ = _::intel_t<-1, 0, 0> {};
202 constexpr inline auto dpcpp_ = _::dpcpp_t<-1, 0, 0> {};
203 constexpr inline auto clang_ = _::clang_t<-1, 0, 0> {};
204 constexpr inline auto gcc_ = _::gcc_t<-1, 0, 0> {};
205 constexpr inline auto emscripten_ = _::emscripten_t<-1, 0, 0> {};
206 constexpr inline auto clangcl_ = _::clangcl_t<-1, 0, 0> {};
207 constexpr inline auto mingw32_ = _::mingw32_t<-1, 0, 0> {};
208 constexpr inline auto mingw64_ = _::mingw64_t<-1, 0, 0> {};
209 }
210
211 namespace spy::literal
212 {
213 //! @ingroup spy_compiler
214 //! @brief User-defined suffix for NVCC version definition
215 template<char... c> constexpr auto operator""_nvcc()
216 {
217 return _::literal_wrap<_::nvcc_t, c...>();
218 }
219
220 //! @ingroup spy_compiler
221 //! @brief User-defined suffix for MSVC version definition
222 template<char... c> constexpr auto operator""_msvc()
223 {
224 return _::literal_wrap<_::msvc_t, c...>();
225 }
226
227 //! @ingroup spy_compiler
228 //! @brief User-defined suffix for MINGW32 version definition
229 template<char... c> constexpr auto operator""_mingw32()
230 {
231 return _::literal_wrap<_::mingw32_t, c...>();
232 }
233
234 //! @ingroup spy_compiler
235 //! @brief User-defined suffix for MINGW64 version definition
236 template<char... c> constexpr auto operator""_mingw64()
237 {
238 return _::literal_wrap<_::mingw64_t, c...>();
239 }
240
241 //! @ingroup spy_compiler
242 //! @brief User-defined suffix for Intel ICC version definition
243 template<char... c> constexpr auto operator""_intel()
244 {
245 return _::literal_wrap<_::intel_t, c...>();
246 }
247
248 //! @ingroup spy_compiler
249 //! @brief User-defined suffix for Intel DCP++/ICPX version definition
250 template<char... c> constexpr auto operator""_dpcpp()
251 {
252 return _::literal_wrap<_::dpcpp_t, c...>();
253 }
254
255 //! @ingroup spy_compiler
256 //! @brief User-defined suffix for Clang version definition
257 template<char... c> constexpr auto operator""_clang()
258 {
259 return _::literal_wrap<_::clang_t, c...>();
260 }
261
262 //! @ingroup spy_compiler
263 //! @brief User-defined suffix for G++ version definition
264 template<char... c> constexpr auto operator""_gcc() { return _::literal_wrap<_::gcc_t, c...>(); }
265
266 //! @ingroup spy_compiler
267 //! @brief User-defined suffix for Emscripten version definition
268 template<char... c> constexpr auto operator""_em()
269 {
270 return _::literal_wrap<_::emscripten_t, c...>();
271 }
272
273 //! @ingroup spy_compiler
274 //! @brief User-defined suffix for ClangCL version definition
275 template<char... c> constexpr auto operator""_clangcl()
276 {
277 return _::literal_wrap<_::clangcl_t, c...>();
278 }
279 }
280