diff --git a/groups/bsl/bsls/bsls_compilerfeatures.h b/groups/bsl/bsls/bsls_compilerfeatures.h index 37cd2bf39c..73d569b365 100644 --- a/groups/bsl/bsls/bsls_compilerfeatures.h +++ b/groups/bsl/bsls/bsls_compilerfeatures.h @@ -21,9 +21,11 @@ BSLS_IDENT("$Id: $") // BSLS_COMPILERFEATURES_SUPPORT_ATTRIBUTE_NODISCARD: `[[nodiscard]]` // BSLS_COMPILERFEATURES_SUPPORT_ATTRIBUTE_NORETURN: `[[noreturn]]` attribute // BSLS_COMPILERFEATURES_SUPPORT_CONCEPTS: C++20 core language concepts +// BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20: `consteval` specifier // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR: `constexpr` specifier // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14: C++14 `constexpr` spec. // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP17: C++17 `constexpr` spec. +// BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20: C++20 'constexpr' spec. // BSLS_COMPILERFEATURES_SUPPORT_COROUTINE: core & lib C++20 coroutine support // BSLS_COMPILERFEATURES_SUPPORT_CTAD: flag for template argument deduction // BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE: flag for `decltype` @@ -228,6 +230,10 @@ BSLS_IDENT("$Id: $") // > supported by the current compiler settings for this platform, as // > defined by ISO C++20. // +// * `BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20` +// > This macro is defined if `consteval`, as defined by ISO C++20, is +// > supported by the current compiler settings for this platform. +// // * `BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR` // > This macro is defined if `constexpr` is supported by the current // > compiler settings for this platform. @@ -244,6 +250,11 @@ BSLS_IDENT("$Id: $") // > by the current compiler settings for this platform. In particular, // > this allows lambda functions to be defined in a `constexpr` function. // +// * `BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20` +// > This macro is defined if 'constexpr' with C++20 semantics is supported +// > by the current compiler settings for this platform. In particular, +// > this allows transient allocations. +// // * `BSLS_COMPILERFEATURES_SUPPORT_COROUTINE` // > This macro is defined if coroutines with C++20 (or later) semantics are // > supported by the current compiler settings, including the existence of @@ -1115,6 +1126,19 @@ BSLS_IDENT("$Id: $") #endif #endif +#if __cplusplus > 201703L || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) + // We test against 201907L instead of the published 202002L. + #if defined(__cpp_constexpr) && __cpp_constexpr >= 201907L + #if defined(__cpp_constexpr_dynamic_alloc) && \ + __cpp_constexpr_dynamic_alloc >= 201907L + #define BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 1 + #endif + #endif + #if defined(__cpp_consteval) && __cpp_consteval >= 201811L + #define BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 1 + #endif +#endif + // ============================================================================ // ATTRIBUTE DETECTION // ============================================================================ diff --git a/groups/bsl/bsls/bsls_compilerfeatures.t.cpp b/groups/bsl/bsls/bsls_compilerfeatures.t.cpp index 77935f815f..e5567f7223 100644 --- a/groups/bsl/bsls/bsls_compilerfeatures.t.cpp +++ b/groups/bsl/bsls/bsls_compilerfeatures.t.cpp @@ -54,9 +54,11 @@ // [27] BSLS_COMPILERFEATURES_SUPPORT_ATTRIBUTE_FALLTHROUGH // [28] BSLS_COMPILERFEATURES_SUPPORT_ATTRIBUTE_MAYBE_UNUSED // [38] BSLS_COMPILERFEATURES_SUPPORT_CONCEPTS +// [40] BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 // [ 2] BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR // [ 3] BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14 // [ 4] BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP17 +// [39] BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 // [37] BSLS_COMPILERFEATURES_SUPPORT_COROUTINE // [34] BSLS_COMPILERFEATURES_SUPPORT_CTAD // [ 5] BSLS_COMPILERFEATURES_SUPPORT_DECLTYPE @@ -92,7 +94,7 @@ // [ ] BSLS_COMPILERFEATURES_FORWARD_REF // [ ] BSLS_COMPILERFEATURES_FORWARD // ---------------------------------------------------------------------------- -// [39] USAGE EXAMPLE +// [41] USAGE EXAMPLE #ifdef BDE_VERIFY // Suppress some pedantic bde_verify checks in this test driver @@ -696,6 +698,20 @@ constexpr int moreRelaxedConstExprFunc(bool b) } #endif // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP17 +#if defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20) +/// Return a different integer value depending on the specified `b` boolean +/// value. Function is declared `consteval` to test support for the keyword. +consteval int constEvalFunc(bool b) +{ + if (b) { + return 6; // RETURN + } + else { + return 7; // RETURN + } +} +#endif // BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 + /// A type to represent `false`. Notice that its size is different from /// that of `TrueType`. struct FalseType { @@ -845,6 +861,68 @@ constexpr int Feature17::call(bool b) { } } #endif // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP17 + +#if defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20) +/// This literal type is for testing C++20 `constexpr` support. +struct ConstexprCpp20TrivialTypeForTest { + // PUBLIC DATA + int d_value; +}; + +/// This literal type is for testing C++20 `constexpr` support. +struct ConstexprCpp20Tester { + + // PUBLIC DATA + int d_value; + + // CREATORS + + /// Create a, possibly `constexpr`, `ConstexprCpp20Tester` object. + constexpr ConstexprCpp20Tester(); + + /// Return, a possibly `constexpr` integer value that depends on the + /// specified `b` flag. This method is "complex", cannot be `constexpr` + /// in C++17, only in C++20 and onwards. + constexpr int call(bool b); + + // ACCESSORS + + // Simple `constexpr virtual` function only supported in C++20. + constexpr virtual int func1(bool b); +}; + +constexpr ConstexprCpp20Tester::ConstexprCpp20Tester() : d_value(-1) +{ +} + +constexpr int ConstexprCpp20Tester::call(bool b) +{ + int r1; + try { + r1 = func1(b); + } + catch (...) { + } + + // default trivial construction (not allowed in C++17) + ConstexprCpp20TrivialTypeForTest tt; + // assign a value to make this constexpr in C++20 + tt = ConstexprCpp20TrivialTypeForTest{}; + + if (b) { + return 10 + r1 + tt.d_value; // RETURN + } + else { + return 20 + r1 + tt.d_value; // RETURN + } +} + +constexpr int ConstexprCpp20Tester::func1(bool b) +{ + return b ? 0 : 1; +} +#endif // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 + #endif // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR } // close unnamed namespace @@ -1589,6 +1667,13 @@ static void printFlags() puts("UNDEFINED"); #endif + fputs("\n BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20: ", stdout); +#ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 + puts(STRINGIFY(BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20)); +#else + puts("UNDEFINED"); +#endif + fputs("\n BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR: ", stdout); #ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR puts(STRINGIFY(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR)); @@ -1610,6 +1695,13 @@ static void printFlags() puts("UNDEFINED"); #endif + fputs("\n BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20: ", stdout); +#ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 + puts(STRINGIFY(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20)); +#else + puts("UNDEFINED"); +#endif + fputs("\n BSLS_COMPILERFEATURES_SUPPORT_COROUTINE: ", stdout); #ifdef BSLS_COMPILERFEATURES_SUPPORT_COROUTINE puts(STRINGIFY(BSLS_COMPILERFEATURES_SUPPORT_COROUTINE)); @@ -2092,7 +2184,7 @@ int main(int argc, char *argv[]) } switch (test) { case 0: - case 39: { + case 41: { // -------------------------------------------------------------------- // USAGE EXAMPLE // @@ -2173,6 +2265,83 @@ int main(int argc, char *argv[]) // compilers) that further, more complicated or even indeterminate behaviors // may arise. #undef THATS_MY_LINE + } break; + case 40: { + // ------------------------------------------------------------------ + // BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 + // + // Concerns: + // 1. `BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20` is defined only + // when the compiler understands the `consteval` keyword. + // + // Plan: + // 1. If `BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20` is defined + // then compile code that uses the `consteval` keyword. + // + // Testing: + // BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 + // ------------------------------------------------------------------ + + MACRO_TEST_TITLE("_SUPPORT_CONSTEVAL_CPP20", + "=================="); + +#ifndef BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 + VERBOSE_PUTS("The feature is not supported in this configuration."); +#else + ASSERT(__cpp_consteval >= 201811L); + + static_assert(constEvalFunc(true) == 6, + "`consteval` is not supported"); +#endif + } break; + case 39: { + // ------------------------------------------------------------------ + // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 + // + // Concerns: + // 1. `BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20` is defined only + // when the compiler is actually able to compile code with relaxed + // constexpr functions that may use try/catch blocks, call virtual + // functions, and perform trivial default initialization. + // + // Plan: + // 1. If `BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20` is defined + // then compile code that uses this feature to define relaxed + // constant expression functions. + // + // Testing: + // BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 + // ------------------------------------------------------------------ + + MACRO_TEST_TITLE("_SUPPORT_CONSTEXPR_CPP20", + "========================"); + +#ifndef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 + VERBOSE_PUTS("The feature is not supported in this configuration."); +#else + ASSERT(__cpp_constexpr >= 201907L); + ASSERT(__cpp_constexpr_dynamic_alloc >= 201907L); + + if (sizeof(Sniffer::test(0)) == + sizeof(FalseType)) { + ASSERT(0 == "C++17 did not detect more relaxed constexpr"); + } + + static_assert(moreRelaxedConstExprFunc(true) == 42, + "Relaxed (C++17) `constexpr` is not supported"); + + if (sizeof(Sniffer::test(0)) == sizeof(FalseType)) { + ASSERT(0 == "C++17 did not detect more relaxed constexpr"); + } + + if (sizeof(Sniffer::test(0)) == sizeof(FalseType)) { + ASSERT(0 == "C++17 did not detect relaxed constexpr"); + } + + if (sizeof(Sniffer::test(0)) == sizeof(FalseType)) { + ASSERT(0 == "C++17 did not detect original constexpr"); + } +#endif } break; case 38: { // -------------------------------------------------------------------- diff --git a/groups/bsl/bsls/bsls_keyword.h b/groups/bsl/bsls/bsls_keyword.h index b2ae8b7e35..e7e620e1a6 100644 --- a/groups/bsl/bsls/bsls_keyword.h +++ b/groups/bsl/bsls/bsls_keyword.h @@ -10,11 +10,13 @@ BSLS_IDENT("$Id: $") //@CLASSES: // //@MACROS: +// BSLS_KEYWORD_CONSTEVAL_CPP20: C++20 `consteval` keyword // BSLS_KEYWORD_CONSTEXPR: C++11 `constexpr` keyword // BSLS_KEYWORD_CONSTEXPR_MEMBER: for `constexpr` data members (Deprecated) // BSLS_KEYWORD_CONSTEXPR_RELAXED: C++14 `constexpr` keyword (Deprecated) // BSLS_KEYWORD_CONSTEXPR_CPP14: C++14 `constexpr` keyword // BSLS_KEYWORD_CONSTEXPR_CPP17: C++17 `constexpr` keyword +// BSLS_KEYWORD_CONSTEXPR_CPP20: C++20 `constexpr` keyword // BSLS_KEYWORD_DELETED: C++11 `= delete` function definition // BSLS_KEYWORD_EXPLICIT: C++11 `explicit` for conversion operators // BSLS_KEYWORD_FINAL: C++11 `final` keyword @@ -40,7 +42,11 @@ BSLS_IDENT("$Id: $") ///------------- // The following are the macros provided by this component. // -//: `BSLS_KEYWORD_CONSTEXPR`: +//: `BSLS_KEYWORD_CONSTEVAL_CPP20`: +//: This macro inserts the keyword `consteval` when compiling with C++20 +//: or later mode and inserts nothing when compiling with earlier modes. +//: +// `BSLS_KEYWORD_CONSTEXPR`: //: This macro inserts the keyword `constexpr` when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. //: @@ -67,6 +73,11 @@ BSLS_IDENT("$Id: $") //: mode. See Example 2 below for a better description of the differences //: between `constexpr` between C++11, C++14, and C++17. //: +//: `BSLS_KEYWORD_CONSTEXPR_CPP20`: +//: This macro inserts the keyword `constexpr` when compiling with C++20 +//: or later mode and inserts nothing when compiling with +//: C++03/C++11/C++14/C++17 mode. +//: //: `BSLS_KEYWORD_DELETED`: //: This macro inserts the text `= delete` when compiling with C++11 //: or later mode and inserts nothing when compiling with C++03 mode. @@ -529,6 +540,12 @@ BSLS_IDENT("$Id: $") #include +#ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20 +# define BSLS_KEYWORD_CONSTEVAL_CPP20 consteval +#else +# define BSLS_KEYWORD_CONSTEVAL_CPP20 +#endif + #ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR # define BSLS_KEYWORD_CONSTEXPR constexpr # define BSLS_KEYWORD_CONSTEXPR_MEMBER constexpr @@ -551,6 +568,12 @@ BSLS_IDENT("$Id: $") # define BSLS_KEYWORD_CONSTEXPR_CPP17 #endif +#ifdef BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20 +#define BSLS_KEYWORD_CONSTEXPR_CPP20 constexpr +#else +#define BSLS_KEYWORD_CONSTEXPR_CPP20 +#endif + #ifdef BSLS_COMPILERFEATURES_SUPPORT_DELETED_FUNCTIONS # define BSLS_KEYWORD_DELETED = delete #else diff --git a/groups/bsl/bsls/bsls_keyword.t.cpp b/groups/bsl/bsls/bsls_keyword.t.cpp index cb9e43807b..12c486a2a0 100644 --- a/groups/bsl/bsls/bsls_keyword.t.cpp +++ b/groups/bsl/bsls/bsls_keyword.t.cpp @@ -22,11 +22,13 @@ using namespace std; // Overview // -------- //----------------------------------------------------------------------------- +// [12] BSLS_KEYWORD_CONSTEVAL_CPP20 // [ 2] BSLS_KEYWORD_CONSTEXPR // [ ] BSLS_KEYWORD_CONSTEXPR_MEMBER // [ 3] BSLS_KEYWORD_CONSTEXPR_RELAXED // [ 3] BSLS_KEYWORD_CONSTEXPR_CPP14 // [ 4] BSLS_KEYWORD_CONSTEXPR_CPP17 +// [11] BSLS_KEYWORD_CONSTEXPR_CPP20 // [10] BSLS_KEYWORD_DELETED // [ 5] BSLS_KEYWORD_EXPLICIT // [ 6] BSLS_KEYWORD_FINAL (class) @@ -39,7 +41,7 @@ using namespace std; // [ 8] BSLS_KEYWORD_NOEXCEPT_SPECIFICATION // [ 9] BSLS_KEYWORD_OVERRIDE //----------------------------------------------------------------------------- -// [11] USAGE EXAMPLE +// [13] USAGE EXAMPLE // [ 1] Test machinery // ============================================================================ @@ -580,7 +582,7 @@ int main(int argc, char *argv[]) } switch (test) { case 0: - case 11: { + case 13: { // -------------------------------------------------------------------- // TESTING USAGE EXAMPLE // @@ -738,6 +740,66 @@ int main(int argc, char *argv[]) #undef FAIL_USAGE_OVERRIDE_TYPE #undef FAIL_USAGE_NO_OVERRIDE } break; + case 12: { + // -------------------------------------------------------------------- + // TESTING: BSLS_KEYWORD_CONSTEVAL_CPP20 + // + // Concerns: + // 1. When `BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20` is defined + // `BSLS_KEYWORD_CONSTEVAL_CPP20` evaluates to `consteval`. + // + // 2. When `BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20` is not + // defined `BSLS_KEYWORD_CONSTEVAL_CPP20` evaluates to nothing. + // + // Plan: + // 1. Compare the stringified value of the macro to an oracle. + // + // Testing: + // BSLS_KEYWORD_CONSTEVAL_CPP20 + // -------------------------------------------------------------------- + + if (verbose) + printf("\nTESTING: BSLS_KEYWORD_CONSTEVAL_CPP20" + "\n=====================================\n"); + + const char *expected = +#if defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEVAL_CPP20) + "consteval"; +#else + ""; +#endif + ASSERT(strcmp(STRINGIFY(BSLS_KEYWORD_CONSTEVAL_CPP20), expected) == 0); + } break; + case 11: { + // -------------------------------------------------------------------- + // TESTING: BSLS_KEYWORD_CONSTEXPR_CPP20 + // + // Concerns: + // 1. When `BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20` is defined + // `BSLS_KEYWORD_CONSTEXPR_CPP20` evaluates to `constexpr`. + // + // 2. When `BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20` is not + // defined `BSLS_KEYWORD_CONSTEXPR_CPP20` evaluates to nothing. + // + // Plan: + // 1. Compare the stringified value of the macro to an oracle. + // + // Testing: + // BSLS_KEYWORD_CONSTEXPR_CPP20 + // -------------------------------------------------------------------- + + if (verbose) + printf("\nTESTING: BSLS_KEYWORD_CONSTEXPR_CPP20" + "\n=====================================\n"); + + const char *expected = +#if defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP20) + "constexpr"; +#else + ""; +#endif + ASSERT(strcmp(STRINGIFY(BSLS_KEYWORD_CONSTEXPR_CPP20), expected) == 0); + } break; case 10: { // -------------------------------------------------------------------- // TESTING: BSLS_KEYWORD_DELETED