1## ---------------------------------------------------------------------
2##
3## Copyright (C) 2012 - 2020 by the deal.II authors
4##
5## This file is part of the deal.II library.
6##
7## The deal.II library is free software; you can use it, redistribute
8## it, and/or modify it under the terms of the GNU Lesser General
9## Public License as published by the Free Software Foundation; either
10## version 2.1 of the License, or (at your option) any later version.
11## The full text of the license can be found in the file LICENSE.md at
12## the top level directory of deal.II.
13##
14## ---------------------------------------------------------------------
15
16#
17# Check for various C++ language features
18#
19# This file sets up
20#
21#   DEAL_II_HAVE_CXX14
22#   DEAL_II_HAVE_CXX17
23#   DEAL_II_HAVE_CXX20
24#
25#   DEAL_II_HAVE_FP_EXCEPTIONS
26#   DEAL_II_HAVE_COMPLEX_OPERATOR_OVERLOADS
27#   DEAL_II_HAVE_CXX17_BESSEL_FUNCTIONS
28#   DEAL_II_FALLTHROUGH
29#   DEAL_II_DEPRECATED
30#   DEAL_II_CONSTEXPR
31#
32
33
34########################################################################
35#                                                                      #
36#                         C++ Version Support:                         #
37#                                                                      #
38########################################################################
39
40
41#
42# We need compiler flags specified in ${DEAL_II_CXX_FLAGS} for all the
43# tests. Create a small macro to easily set CMAKE_REQUIRED_FLAGS
44#
45MACRO(_set_up_cmake_required)
46  # Let's put the user supplied `DEAL_II_CXX_FLAGS_SAVED` last so that we
47  # never override a user supplied -std=c++XY flag in our tests.
48  RESET_CMAKE_REQUIRED()
49  SET(CMAKE_REQUIRED_FLAGS "")
50  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS}")
51  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${DEAL_II_CXX_FLAGS_SAVED}")
52ENDMACRO()
53
54
55#
56# Wrap the following checks into a macro to make it easier to rerun them.
57#
58MACRO(_test_cxx20_support)
59
60  UNSET_IF_CHANGED(CHECK_CXX20_FEATURES_FLAGS_SAVED
61    "${CMAKE_REQUIRED_FLAGS}"
62    DEAL_II_HAVE_CXX20_FEATURES
63    )
64
65  # Strictly speaking "201709L" indicates support for a preliminary version
66  # of C++20 standard (which will have "202002L" when finalized). gcc-10
67  # exports this version number when configured with C++20 support.
68  # clang-10 exports the final "202002L" version instead.
69  CHECK_CXX_SOURCE_COMPILES(
70    "
71    #include <cmath>
72    #include <ranges>
73
74    #if __cplusplus < 201709L && !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
75    #  error \"insufficient support for C++20\"
76    #endif
77
78    #if !(defined __cpp_lib_ranges) || (__cpp_lib_ranges < 201911)
79    #  error \"insufficient support for C++20\"
80    #endif
81
82    int main()
83    {
84    }
85    "
86    DEAL_II_HAVE_CXX20_FEATURES)
87
88  IF(DEAL_II_HAVE_CXX20_FEATURES)
89    MESSAGE(STATUS "C++20 support is enabled.")
90    SET(DEAL_II_HAVE_CXX20 TRUE)
91  ELSE()
92    MESSAGE(STATUS "C++20 support is disabled.")
93    SET(DEAL_II_HAVE_CXX20 FALSE)
94  ENDIF()
95ENDMACRO()
96
97
98#
99# Wrap the following checks into a macro to make it easier to rerun them.
100#
101MACRO(_test_cxx17_support)
102
103  UNSET_IF_CHANGED(CHECK_CXX17_FEATURES_FLAGS_SAVED
104    "${CMAKE_REQUIRED_FLAGS}"
105    DEAL_II_HAVE_CXX17_FEATURES
106    DEAL_II_HAVE_CXX17_CONSTEXPR_LAMBDA_BUG_OK
107    )
108
109  CHECK_CXX_SOURCE_COMPILES(
110    "
111    #include <iostream>
112    #include <optional>
113    #include <tuple>
114
115    #if __cplusplus < 201703L && !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
116    #  error \"insufficient support for C++17\"
117    #endif
118
119    //check for some C++17 features that we use in our headers:
120    using std::apply;
121    using std::optional;
122
123    [[nodiscard]] int test_nodiscard()
124    {
125      return 1;
126    }
127
128    int main()
129    {
130      const unsigned int n=1;
131      switch (n)
132      {
133        case 1:
134          std::cout << n;
135          [[fallthrough]];
136        case 2:
137          std::cout << n;
138      }
139
140      [[maybe_unused]] int i = test_nodiscard();
141
142      constexpr bool flag = false;
143      if constexpr(flag)
144        return 1;
145      return 0;
146    }
147    "
148    DEAL_II_HAVE_CXX17_FEATURES)
149
150  # Some compilers treat lambdas as constexpr functions when compiling with
151  # C++17 support even if they don't fulfill all the constexpr function
152  # requirements. Consequently, these compilers don't allow try-blocks or
153  # non-literal return types in lambdas. This is a bug.
154  CHECK_CXX_SOURCE_COMPILES(
155    "
156    #include <string>
157    int main()
158    {
159      auto c = []()
160      {
161        return std::string{};
162      }();
163      (void) c;
164
165      return []()
166      {
167        try
168        {}
169        catch(...)
170        {}
171        return 0;
172      }();
173    }
174    "
175    DEAL_II_HAVE_CXX17_CONSTEXPR_LAMBDA_BUG_OK)
176
177  IF(DEAL_II_HAVE_CXX17_FEATURES AND
178     DEAL_II_HAVE_CXX17_CONSTEXPR_LAMBDA_BUG_OK)
179    MESSAGE(STATUS "C++17 support is enabled.")
180    SET(DEAL_II_HAVE_CXX17 TRUE)
181  ELSE()
182    MESSAGE(STATUS "C++17 support is disabled.")
183    SET(DEAL_II_HAVE_CXX17 FALSE)
184  ENDIF()
185ENDMACRO()
186
187
188#
189# Wrap the following checks into a macro to make it easier to rerun them.
190#
191MACRO(_test_cxx14_support)
192  UNSET_IF_CHANGED(CHECK_CXX14_FEATURES_FLAGS_SAVED
193    "${CMAKE_REQUIRED_FLAGS}"
194    DEAL_II_HAVE_CXX14_FEATURES
195    DEAL_II_HAVE_CXX14_CLANGAUTODEBUG_BUG_OK
196    DEAL_II_HAVE_CXX11_FEATURES
197    DEAL_II_HAVE_CXX11_FUNCTIONAL_LLVMBUG20084_OK
198    )
199
200  # Check some generic C++14 features
201  CHECK_CXX_SOURCE_COMPILES(
202    "
203    #include <memory>
204    #include <algorithm>
205
206    // Check the version language macro, but skip MSVC because
207    // MSVC reports 199711 even in MSVC 2017.
208    #if __cplusplus < 201402L && !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
209    #  error \"insufficient support for C++14\"
210    #endif
211
212    int main()
213    {
214      auto ptr = std::make_unique<int>(42);
215      constexpr int max = std::max(0, 1);
216      (void) ptr;
217      (void) max;
218      return 0;
219    }
220    "
221    DEAL_II_HAVE_CXX14_FEATURES)
222
223  # Clang-3.5* or older, bail out with a spurious error message in case
224  # of an undeduced auto return type.
225  #
226  # https://llvm.org/bugs/show_bug.cgi?id=16876
227  SET(_flags "${DEAL_II_CXX_FLAGS_DEBUG}")
228  STRIP_FLAG(_flags "-Wa,--compress-debug-sections")
229  ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_flags}")
230  CHECK_CXX_SOURCE_COMPILES(
231    "
232    struct foo
233    {
234      auto func();
235    };
236    int main()
237    {
238      foo bar;
239      (void) bar;
240    }
241    "
242    DEAL_II_HAVE_CXX14_CLANGAUTODEBUG_BUG_OK)
243
244  # Check some generic C++11 features
245  CHECK_CXX_SOURCE_COMPILES(
246    "
247    // common C++11 include files
248    #include <array>
249    #include <condition_variable>
250    #include <type_traits>
251
252    // thread_local storage specification
253    static thread_local std::array<int,3> p;
254
255    // Check the version language macro, but skip MSVC because
256    // MSVC reports 199711 even in MSVC 2017.
257    #if __cplusplus < 201103L && !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
258    #  error \"insufficient support for C++11\"
259    #endif
260
261    int main()
262    {
263      std::condition_variable c;
264      p[0] = 1;
265      c.notify_all();
266
267     // type traits functionality
268     constexpr auto m0 = std::is_trivial<double>::value;
269     (void) m0;
270     constexpr auto m1 = std::is_standard_layout<double>::value;
271     (void) m1;
272     constexpr auto m2 = std::is_pod<double>::value;
273     (void) m2;
274    }
275    "
276    DEAL_II_HAVE_CXX11_FEATURES)
277
278  # clang libc++ bug, see https://llvm.org/bugs/show_bug.cgi?id=20084
279  CHECK_CXX_SOURCE_COMPILES(
280    "
281    #include <functional>
282    struct A { void foo() const {} };
283    int main() { A a; std::bind(&A::foo,a)(); return 0; }
284    "
285    DEAL_II_HAVE_CXX11_FUNCTIONAL_LLVMBUG20084_OK)
286
287  IF(DEAL_II_HAVE_CXX14_FEATURES AND
288     DEAL_II_HAVE_CXX14_CLANGAUTODEBUG_BUG_OK AND
289     DEAL_II_HAVE_CXX11_FEATURES AND
290     DEAL_II_HAVE_CXX11_FUNCTIONAL_LLVMBUG20084_OK)
291    MESSAGE(STATUS "C++14 support is enabled.")
292    SET(DEAL_II_HAVE_CXX14 TRUE)
293  ELSE()
294    MESSAGE(STATUS "C++14 support is disabled.")
295    SET(DEAL_II_HAVE_CXX14 FALSE)
296  ENDIF()
297ENDMACRO()
298
299
300#
301# Try to find out what we support:
302#
303
304_set_up_cmake_required()
305_test_cxx14_support()
306
307IF(NOT DEAL_II_HAVE_CXX14)
308  MESSAGE(STATUS "C++14 support not available. Try to set -std=c++14 explicitly")
309  ENABLE_IF_SUPPORTED(DEAL_II_CXX_FLAGS "-std=c++14")
310  _set_up_cmake_required()
311  _test_cxx14_support()
312ENDIF()
313
314IF(NOT DEAL_II_HAVE_CXX14)
315  MESSAGE(FATAL_ERROR
316    "\nThe current version of deal.II requires a compiler with enabled "
317    "C++14 support. Make sure to use a modern enough compiler (GCC version "
318    "5 onwards, Clang version 4 onwards, or Microsoft MS VS 2015 onwards) "
319    "and check that the compiler flag \"-std=\" is either unset, or set to "
320    "at least c++14.\n\n"
321    )
322ENDIF()
323
324_test_cxx17_support()
325_test_cxx20_support()
326
327
328########################################################################
329#                                                                      #
330#                   Check for various C++ features:                    #
331#                                                                      #
332########################################################################
333
334
335#
336# Some compilers are too generous in accepting some of the language
337# features that we test below and do not issue an error but a warning. Set
338# -Werror to make the feature detection more reliable.
339#
340SET(_werror_flag "")
341IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
342  ENABLE_IF_SUPPORTED(_werror_flag "/WX /EHsc")
343ELSE()
344  ENABLE_IF_SUPPORTED(_werror_flag "-Werror")
345  ENABLE_IF_SUPPORTED(_werror_flag "-Wno-unused-command-line-argument")
346ENDIF()
347ADD_FLAGS(CMAKE_REQUIRED_FLAGS "${_werror_flag}")
348
349UNSET_IF_CHANGED(CHECK_CXX_FEATURES_FLAGS_SAVED
350  "${CMAKE_REQUIRED_FLAGS}"
351  DEAL_II_HAVE_FP_EXCEPTIONS
352  DEAL_II_HAVE_COMPLEX_OPERATOR_OVERLOADS
353  DEAL_II_HAVE_CXX17_ATTRIBUTE_DEPRECATED
354  DEAL_II_HAVE_ATTRIBUTE_DEPRECATED
355  DEAL_II_HAVE_CXX17_ATTRIBUTE_FALLTHROUGH
356  DEAL_II_HAVE_ATTRIBUTE_FALLTHROUGH
357  DEAL_II_HAVE_CXX17_BESSEL_FUNCTIONS
358  DEAL_II_CXX14_CONSTEXPR_BUG_OK
359  )
360
361
362#
363# Check that we can use feenableexcept through the C++11 header file cfenv:
364#
365# The test is a bit more complicated because we also check that no garbage
366# exception is thrown if we convert -std::numeric_limits<double>::max to a
367# string. This sadly happens with some compiler support libraries :-(
368#
369# - Timo Heister, 2015
370#
371SET(_snippet
372  "
373  #include <cfenv>
374  #include <limits>
375  #include <sstream>
376
377  int main()
378  {
379    feenableexcept(FE_DIVBYZERO|FE_INVALID);
380    std::ostringstream description;
381    const double lower_bound = -std::numeric_limits<double>::max();
382
383    description << lower_bound;
384
385    return 0;
386  }
387  "
388  )
389IF(DEAL_II_ALLOW_PLATFORM_INTROSPECTION)
390  CHECK_CXX_SOURCE_RUNS("${_snippet}" DEAL_II_HAVE_FP_EXCEPTIONS)
391ELSE()
392  #
393  # If we are not allowed to do platform introspection, just test whether
394  # we can compile above code.
395  #
396  CHECK_CXX_SOURCE_COMPILES("${_snippet}" DEAL_II_HAVE_FP_EXCEPTIONS)
397ENDIF()
398
399
400#
401# Check whether the standard library provides operator* overloads for mixed
402# floating point multiplication of complex and real valued numbers.
403#
404# - Matthias Maier, 2015
405#
406CHECK_CXX_SOURCE_COMPILES(
407  "
408  #include <complex>
409
410  int main()
411  {
412    double() * std::complex<float>();
413    std::complex<float>() * double();
414    float() * std::complex<double>();
415    std::complex<double>() * float();
416    std::complex<double>() * std::complex<float>();
417    std::complex<float>() * std::complex<double>();
418
419    return 0;
420  }
421  "
422  DEAL_II_HAVE_COMPLEX_OPERATOR_OVERLOADS)
423
424
425#
426# Even though [[deprecated]] is a C++14 feature we have to check
427# wether we can actually use the [[deprecated]] attribute in all
428# cases we care about; some of the following are C++17 features.
429#
430CHECK_CXX_SOURCE_COMPILES(
431  "
432  [[deprecated]] int old_fn ();
433  int old_fn () { return 0; }
434
435  struct [[deprecated]] bob
436  {
437    [[deprecated]] bob(int i);
438    [[deprecated]] void test();
439  };
440
441  enum color
442  {
443    red [[deprecated]]
444  };
445
446  template <int dim>
447  struct foo {};
448  using bar [[deprecated]] = foo<2>;
449
450  int main () {}
451  "
452  DEAL_II_HAVE_CXX17_ATTRIBUTE_DEPRECATED
453  )
454
455#
456# Also test the corresponding GCC extension
457#
458CHECK_CXX_SOURCE_COMPILES(
459  "
460  __attribute__((deprecated)) int old_fn ();
461  int old_fn () { return 0; }
462
463  struct __attribute__((deprecated)) bob
464  {
465    __attribute__((deprecated)) bob(int i);
466    __attribute__((deprecated)) void test();
467  };
468
469  enum color
470  {
471    red __attribute__((deprecated))
472  };
473
474  template <int dim>
475  struct foo {};
476  using bar __attribute__((deprecated)) = foo<2>;
477
478  int main () {}
479  "
480  DEAL_II_HAVE_ATTRIBUTE_DEPRECATED
481  )
482
483IF(DEAL_II_HAVE_CXX17_ATTRIBUTE_DEPRECATED)
484  SET(DEAL_II_DEPRECATED "[[deprecated]]")
485ELSEIF(DEAL_II_HAVE_ATTRIBUTE_DEPRECATED AND NOT DEAL_II_WITH_CUDA)
486  SET(DEAL_II_DEPRECATED "__attribute__((deprecated))")
487ELSE()
488  SET(DEAL_II_DEPRECATED " ")
489ENDIF()
490
491
492#
493# Try to enable a fallthrough attribute. This is a language feature in C++17,
494# but a compiler extension in earlier language versions.
495#
496CHECK_CXX_SOURCE_COMPILES(
497  "
498  int main()
499  {
500    int i = 42;
501    int j = 10;
502    switch(i)
503      {
504      case 1:
505        ++j;
506        [[fallthrough]];
507      case 2:
508        ++j;
509        [[fallthrough]];
510      default:
511        break;
512      }
513   }
514   "
515   DEAL_II_HAVE_CXX17_ATTRIBUTE_FALLTHROUGH
516   )
517
518#
519# see if the current compiler configuration supports the GCC extension
520# __attribute__((fallthrough)) syntax instead
521#
522CHECK_CXX_SOURCE_COMPILES(
523  "
524  int main()
525  {
526    int i = 42;
527    int j = 10;
528    switch(i)
529      {
530      case 1:
531        ++j;
532        __attribute__((fallthrough));
533      case 2:
534        ++j;
535        __attribute__((fallthrough));
536      default:
537        break;
538      }
539  }
540  "
541  DEAL_II_HAVE_ATTRIBUTE_FALLTHROUGH
542  )
543
544IF(DEAL_II_HAVE_CXX17_ATTRIBUTE_FALLTHROUGH)
545  SET(DEAL_II_FALLTHROUGH "[[fallthrough]]")
546ELSEIF(DEAL_II_HAVE_ATTRIBUTE_FALLTHROUGH)
547  SET(DEAL_II_FALLTHROUGH "__attribute__((fallthrough))")
548ELSE()
549  SET(DEAL_II_FALLTHROUGH " ")
550ENDIF()
551
552
553#
554# Check for c++17 bessel function support. Unfortunately libc++ version 10
555# does not have those.
556#
557
558CHECK_CXX_SOURCE_COMPILES(
559  "
560  #include <cmath>
561  using std::cyl_bessel_j;
562  using std::cyl_bessel_jf;
563  using std::cyl_bessel_jl;
564  int main()
565  {
566  }
567  "
568  DEAL_II_HAVE_CXX17_BESSEL_FUNCTIONS
569  )
570
571
572#
573# Check for correct c++14 constexpr support.
574#
575# As long as there exists an argument value such that an invocation of the
576# function or constructor could be an evaluated subexpression of a core constant
577# expression, C++14 allows to call non-constexpr functions from constexpr
578# functions.
579#
580# Unfortunately, not all compilers obey the standard in this regard. In some
581# cases, MSVC 2019 crashes with an internal compiler error when we
582# declare the respective functions as 'constexpr' even though the test below
583# passes, see #9080.
584#
585# We only run this check if we have CXX14 support, otherwise the use of constexpr
586# is limited (non-const constexpr functions for example).
587#
588
589# MSVC has considerable problems with "constexpr", disable unconditionally
590# for now
591IF(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
592  SET(DEAL_II_CXX14_CONSTEXPR_BUG true)
593ELSE()
594  CHECK_CXX_COMPILER_BUG(
595    "
596    #define Assert(x,y) if (!(x)) throw y;
597    void bar()
598    {}
599
600    constexpr int
601    foo(const int n)
602    {
603      Assert(n>0, \"hello\");
604      if(!(n >= 0))
605        bar();
606      return n;
607    }
608
609    int main()
610    {
611      constexpr unsigned int n=foo(1);
612      return n;
613    }
614    "
615    DEAL_II_CXX14_CONSTEXPR_BUG)
616ENDIF()
617
618SET(DEAL_II_CONSTEXPR "constexpr")
619IF(DEAL_II_CXX14_CONSTEXPR_BUG)
620  SET(DEAL_II_CONSTEXPR " ")
621ENDIF()
622
623
624RESET_CMAKE_REQUIRED()
625