Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -873,6 +873,45 @@ ``__has_extension(cxx_variable_templates)`` to determine if support for templated variable declarations is enabled. +C++1z +----- + +C++1z fold expressions +^^^^^^^^^^^^^^^^^^^^^^ + +Use ``__has_feature(cxx_fold_expressions)`` or +``__has_extension(cxx_fold_expressions)`` to determine if support for +fold expressions is enabled. + +C++1z if constexpr +^^^^^^^^^^^^^^^^^^ + +Use ``__has_feature(cxx_if_constexpr)`` or +``__has_extension(cxx_if_constexpr)`` to determine if support for +if constexpr is enabled. + +C++1z inline variables +^^^^^^^^^^^^^^^^^^^^^^ + +Use ``__has_feature(cxx_inline_variables)`` or +``__has_extension(cxx_inline_variables)`` to determine if support for +inline variables is enabled. + +C++1z structured bindings +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Use ``__has_feature(cxx_structured_bindings)`` or +``__has_extension(cxx_structured_bindings)`` to determine if support for +structured bindings is enabled. + +C++1z variadic using +^^^^^^^^^^^^^^^^^^^^ + +Use ``__has_feature(cxx_variadic_using)`` or +``__has_extension(cxx_variadic_using)`` to determine if support for +variadic using is enabled. + + C11 --- Index: lib/Lex/PPMacroExpansion.cpp =================================================================== --- lib/Lex/PPMacroExpansion.cpp +++ lib/Lex/PPMacroExpansion.cpp @@ -1224,8 +1224,15 @@ .Case("cxx_relaxed_constexpr", LangOpts.CPlusPlus14) .Case("cxx_return_type_deduction", LangOpts.CPlusPlus14) .Case("cxx_variable_templates", LangOpts.CPlusPlus14) + // C++17 features + .Case("cxx_fold_expressions", LangOpts.CPlusPlus1z) + .Case("cxx_if_constexpr", LangOpts.CPlusPlus1z) + .Case("cxx_inline_variables", LangOpts.CPlusPlus1z) + .Case("cxx_structured_bindings", LangOpts.CPlusPlus1z) + .Case("cxx_variadic_using", LangOpts.CPlusPlus1z) // NOTE: For features covered by SD-6, it is preferable to provide *only* - // the SD-6 macro and not a __has_feature check. + // the SD-6 macro and not a __has_feature check unless the feature is + // also provided as an extension in older dialects. // C++ TSes //.Case("cxx_runtime_arrays", LangOpts.CPlusPlusTSArrays) @@ -1314,6 +1321,12 @@ .Case("cxx_binary_literals", true) .Case("cxx_init_captures", LangOpts.CPlusPlus11) .Case("cxx_variable_templates", LangOpts.CPlusPlus) + // C++17 features supported by other languages as extensions. + .Case("cxx_fold_expressions", LangOpts.CPlusPlus11) + .Case("cxx_if_constexpr", LangOpts.CPlusPlus11) + .Case("cxx_inline_variables", LangOpts.CPlusPlus11) + .Case("cxx_structured_bindings", LangOpts.CPlusPlus11) + .Case("cxx_variadic_using", LangOpts.CPlusPlus11) .Default(false); } Index: test/Lexer/has_extension_cxx.cpp =================================================================== --- test/Lexer/has_extension_cxx.cpp +++ test/Lexer/has_extension_cxx.cpp @@ -66,3 +66,33 @@ #if __has_extension(cxx_init_captures) int has_init_captures(); #endif + +// CHECK-NOT: has_fold_expressions +// CHECK11: has_fold_expressions +#if __has_extension(cxx_fold_expressions) +int has_fold_expressions(); +#endif + +// CHECK-NOT: has_if_constexpr +// CHECK11: has_if_constexpr +#if __has_extension(cxx_if_constexpr) +int has_if_constexpr(); +#endif + +// CHECK-NOT: has_inline_variables +// CHECK11: has_inline_variables +#if __has_extension(cxx_inline_variables) +int has_inline_variables(); +#endif + +// CHECK-NOT: has_structured_bindings +// CHECK11: has_structured_bindings +#if __has_extension(cxx_structured_bindings) +int has_structured_bindings(); +#endif + +// CHECK-NOT: has_variadic_using +// CHECK11: has_variadic_using +#if __has_extension(cxx_variadic_using) +int has_variadic_using(); +#endif Index: test/Lexer/has_feature_cxx0x.cpp =================================================================== --- test/Lexer/has_feature_cxx0x.cpp +++ test/Lexer/has_feature_cxx0x.cpp @@ -479,3 +479,57 @@ // CHECK-14: has_generic_lambdas // CHECK-11: no_generic_lambdas // CHECK-NO-11: no_generic_lambdas + +#if __has_feature(cxx_fold_expressions) +int has_fold_expressions(); +#else +int no_fold_expressions(); +#endif +// CHECK-1Z: has_fold_expressions +// CHECK-14: no_fold_expressions +// CHECK-11: no_fold_expressions +// CHECK-NO-11: no_fold_expressions + + +#if __has_feature(cxx_if_constexpr) +int has_if_constexpr(); +#else +int no_if_constexpr(); +#endif +// CHECK-1Z: has_if_constexpr +// CHECK-14: no_if_constexpr +// CHECK-11: no_if_constexpr +// CHECK-NO-11: no_if_constexpr + + +#if __has_feature(cxx_inline_variables) +int has_inline_variables(); +#else +int no_inline_variables(); +#endif +// CHECK-1Z: has_inline_variables +// CHECK-14: no_inline_variables +// CHECK-11: no_inline_variables +// CHECK-NO-11: no_inline_variables + + +#if __has_feature(cxx_structured_bindings) +int has_structured_bindings(); +#else +int no_structured_bindings(); +#endif +// CHECK-1Z: has_structured_bindings +// CHECK-14: no_structured_bindings +// CHECK-11: no_structured_bindings +// CHECK-NO-11: no_structured_bindings + + +#if __has_feature(cxx_variadic_using) +int has_variadic_using(); +#else +int no_variadic_using(); +#endif +// CHECK-1Z: has_variadic_using +// CHECK-14: no_variadic_using +// CHECK-11: no_variadic_using +// CHECK-NO-11: no_variadic_using Index: test/SemaCXX/cxx1z-extensions.cpp =================================================================== --- /dev/null +++ test/SemaCXX/cxx1z-extensions.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -std=c++11 -Wno-c++1z-extensions -Wno-c++14-extensions -verify %s + +// expected-no-diagnostics + +// Fold Expressions // +static_assert(__has_extension(cxx_fold_expressions), ""); +template +constexpr bool test_fold_expressions(Bools ...b) { + return (b && ...); +} +static_assert(test_fold_expressions(true, true, true), ""); + +// If Constexpr // +static_assert(__has_extension(cxx_if_constexpr), ""); +template +constexpr bool test_if_constexpr() { + if constexpr (Pred) { + static_assert(Pred, ""); + return true; + } else { + static_assert(!Pred, ""); + return false; + } +} +static_assert(test_if_constexpr(), ""); +static_assert(!test_if_constexpr(), ""); + +// Inline Variables // +static_assert(__has_extension(cxx_inline_variables), ""); +inline int test_inline_variables = 42; + +// Structured Bindings // +static_assert(__has_extension(cxx_structured_bindings), ""); +struct Tuple { + int a, b, c; +}; +constexpr bool test_bindings() { + auto [a, b, c] = Tuple{42, 101, -1}; + return a == 42 && b == 101 && c == -1; +} +static_assert(test_bindings(), ""); + +// Variadic Using // +static_assert(__has_extension(cxx_variadic_using), ""); +struct A { constexpr bool operator()() const { return true; } }; +struct B { constexpr bool operator()(int) const { return false; } }; +template struct TestVariadicUsing : Args... { + using Args::operator()...; +}; +static_assert(TestVariadicUsing{}(), ""); +static_assert(!TestVariadicUsing{}(42), "");