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