On Mon, Jul 31, 2017 at 4:33 PM, Ben Pfaff <[email protected]> wrote: > On Mon, Jul 31, 2017 at 01:05:32PM -0700, Ben Pfaff wrote: >> On Mon, Jul 31, 2017 at 03:50:59PM -0400, Russell Bryant wrote: >> > On Sun, Jul 30, 2017 at 10:54 PM, Ben Pfaff <[email protected]> wrote: >> > > This should help address a recurring problem. >> > > >> > > Signed-off-by: Ben Pfaff <[email protected]> >> > > --- >> > > .travis.yml | 1 + >> > > Makefile.am | 1 + >> > > configure.ac | 2 ++ >> > > include/openvswitch/automake.mk | 14 ++++++++++++++ >> > > m4/openvswitch.m4 | 21 +++++++++++++++++++++ >> > > 5 files changed, 39 insertions(+) >> > >> > Why does this patch depend on libboost? It looks like it's only used >> > when building a test C++ program in configure. We could build a test >> > C++ program without the dependency, right? >> >> It's because of include/openvswitch/compiler.h, which has: >> >> #elif defined(__cplusplus) >> #include <boost/static_assert.hpp> >> #define BUILD_ASSERT BOOST_STATIC_ASSERT >> #define BUILD_ASSERT_DECL BOOST_STATIC_ASSERT >>
Ah, sorry ... >> We could probably define our own C++-compatible static assert without >> boost. It looks like C++11 and later has a built-in static_assert: >> http://en.cppreference.com/w/cpp/language/static_assert >> >> Any idea whether it's reasonable to assume C++11 support these days? I don't know, but that seems pretty reasonable to me. I suppose if it becomes an issue, we could re-add the boost version as an optional dependency that would get used only if C++11 wasn't available? Acked-by: Russell Bryant <[email protected]> > > Here's a version of the patch that gets rid of the boost dependency. It > adds a C++11 dependency instead. > > --8<--------------------------cut here-------------------------->8-- > > From: Ben Pfaff <[email protected]> > Date: Mon, 31 Jul 2017 13:31:43 -0700 > Subject: [PATCH] Automatically verify that OVS header files work OK in C++ > also. > > This should help address a recurring problem. > > Signed-off-by: Ben Pfaff <[email protected]> > --- > Makefile.am | 1 + > configure.ac | 2 + > include/openflow/openflow-common.h | 3 +- > include/openvswitch/automake.mk | 14 + > include/openvswitch/compiler.h | 5 +- > m4/ax_cxx_compile_stdcxx.m4 | 982 > +++++++++++++++++++++++++++++++++++++ > m4/openvswitch.m4 | 16 + > 7 files changed, 1018 insertions(+), 5 deletions(-) > create mode 100644 m4/ax_cxx_compile_stdcxx.m4 > > diff --git a/Makefile.am b/Makefile.am > index 9679379defef..373ef6e9189f 100644 > --- a/Makefile.am > +++ b/Makefile.am > @@ -108,6 +108,7 @@ MAN_ROOTS = > noinst_DATA = > noinst_HEADERS = > lib_LTLIBRARIES = > +noinst_LTLIBRARIES = > noinst_man_MANS = > noinst_PROGRAMS = > noinst_SCRIPTS = > diff --git a/configure.ac b/configure.ac > index 194c4b92ee34..093b6ffed50e 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -23,6 +23,7 @@ AM_INIT_AUTOMAKE([tar-pax]) > > AC_PROG_CC_C99 > AM_PROG_CC_C_O > +AC_PROG_CXX > AC_PROG_CPP > AC_PROG_MKDIR_P > AC_PROG_FGREP > @@ -135,6 +136,7 @@ OVS_CHECK_POSIX_AIO > OVS_CHECK_PTHREAD_SET_NAME > OVS_CHECK_LINUX_HOST > OVS_LIBTOOL_VERSIONS > +OVS_CHECK_CXX > AX_FUNC_POSIX_MEMALIGN > > OVS_CHECK_INCLUDE_NEXT([stdio.h string.h]) > diff --git a/include/openflow/openflow-common.h > b/include/openflow/openflow-common.h > index 410f392d20cd..5f1e22589ced 100644 > --- a/include/openflow/openflow-common.h > +++ b/include/openflow/openflow-common.h > @@ -60,8 +60,7 @@ > extern int (*build_assert(void))[ sizeof(struct { \ > unsigned int build_assert_failed : (EXPR) ? 1 : -1; })] > #else /* __cplusplus */ > -#include <boost/static_assert.hpp> > -#define OFP_ASSERT BOOST_STATIC_ASSERT > +#define OFP_ASSERT(EXPR) static_assert(EXPR, "assertion failed") > #endif /* __cplusplus */ > > /* Version number: > diff --git a/include/openvswitch/automake.mk b/include/openvswitch/automake.mk > index 699d9d74ecd0..74b31acfa66b 100644 > --- a/include/openvswitch/automake.mk > +++ b/include/openvswitch/automake.mk > @@ -30,3 +30,17 @@ openvswitchinclude_HEADERS = \ > include/openvswitch/version.h \ > include/openvswitch/vconn.h \ > include/openvswitch/vlog.h > + > +if HAVE_CXX > +# OVS does not use C++ itself, but it provides public header files > +# that a C++ compiler should accept, so when --enable-Werror is in > +# effect and a C++ compiler is available, we build a C++ source file > +# that #includes all the public headers, as a way to ensure that they > +# are acceptable as C++. > +noinst_LTLIBRARIES += include/openvswitch/libcxxtest.la > +nodist_include_openvswitch_libcxxtest_la_SOURCES = > include/openvswitch/cxxtest.cc > +include/openvswitch/cxxtest.cc: include/openvswitch/automake.mk > + $(AM_V_GEN)for header in $(openvswitchinclude_HEADERS); do \ > + echo $$header; \ > + done | sed 's,^include/\(.*\)$$,#include <\1>,' > $@ > +endif > diff --git a/include/openvswitch/compiler.h b/include/openvswitch/compiler.h > index 0dc8636add33..0076ad763578 100644 > --- a/include/openvswitch/compiler.h > +++ b/include/openvswitch/compiler.h > @@ -244,9 +244,8 @@ > #define BUILD_ASSERT(EXPR) ((void) 0) > #define BUILD_ASSERT_DECL(EXPR) extern int (*build_assert(void))[1] > #elif defined(__cplusplus) > -#include <boost/static_assert.hpp> > -#define BUILD_ASSERT BOOST_STATIC_ASSERT > -#define BUILD_ASSERT_DECL BOOST_STATIC_ASSERT > +#define BUILD_ASSERT(EXPR) static_assert(EXPR, "assertion failed") > +#define BUILD_ASSERT_DECL(EXPR) static_assert(EXPR, "assertion failed") > #elif (__GNUC__ * 256 + __GNUC_MINOR__ >= 0x403 \ > || __has_extension(c_static_assert)) > #define BUILD_ASSERT_DECL(EXPR) _Static_assert(EXPR, #EXPR) > diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 > new file mode 100644 > index 000000000000..5032bba8091d > --- /dev/null > +++ b/m4/ax_cxx_compile_stdcxx.m4 > @@ -0,0 +1,982 @@ > +# =========================================================================== > +# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html > +# =========================================================================== > +# > +# SYNOPSIS > +# > +# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) > +# > +# DESCRIPTION > +# > +# Check for baseline language coverage in the compiler for the specified > +# version of the C++ standard. If necessary, add switches to CXX and > +# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) > +# or '14' (for the C++14 standard). > +# > +# The second argument, if specified, indicates whether you insist on an > +# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. > +# -std=c++11). If neither is specified, you get whatever works, with > +# preference for an extended mode. > +# > +# The third argument, if specified 'mandatory' or if left unspecified, > +# indicates that baseline support for the specified C++ standard is > +# required and that the macro should error out if no mode with that > +# support is found. If specified 'optional', then configuration proceeds > +# regardless, after defining HAVE_CXX${VERSION} if and only if a > +# supporting mode is found. > +# > +# LICENSE > +# > +# Copyright (c) 2008 Benjamin Kosnik <[email protected]> > +# Copyright (c) 2012 Zack Weinberg <[email protected]> > +# Copyright (c) 2013 Roy Stogner <[email protected]> > +# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov > <[email protected]> > +# Copyright (c) 2015 Paul Norman <[email protected]> > +# Copyright (c) 2015 Moritz Klammler <[email protected]> > +# Copyright (c) 2016 Krzesimir Nowak <[email protected]> > +# > +# Copying and distribution of this file, with or without modification, are > +# permitted in any medium without royalty provided the copyright notice > +# and this notice are preserved. This file is offered as-is, without any > +# warranty. > + > +#serial 7 > + > +dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro > +dnl (serial version number 13). > + > +AX_REQUIRE_DEFINED([AC_MSG_WARN]) > +AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl > + m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], > + [$1], [14], [ax_cxx_compile_alternatives="14 1y"], > + [$1], [17], [ax_cxx_compile_alternatives="17 1z"], > + [m4_fatal([invalid first argument `$1' to > AX_CXX_COMPILE_STDCXX])])dnl > + m4_if([$2], [], [], > + [$2], [ext], [], > + [$2], [noext], [], > + [m4_fatal([invalid second argument `$2' to > AX_CXX_COMPILE_STDCXX])])dnl > + m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], > + [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], > + [$3], [optional], [ax_cxx_compile_cxx$1_required=false], > + [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) > + AC_LANG_PUSH([C++])dnl > + ac_success=no > + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, > + ax_cv_cxx_compile_cxx$1, > + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], > + [ax_cv_cxx_compile_cxx$1=yes], > + [ax_cv_cxx_compile_cxx$1=no])]) > + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then > + ac_success=yes > + fi > + > + m4_if([$2], [noext], [], [dnl > + if test x$ac_success = xno; then > + for alternative in ${ax_cxx_compile_alternatives}; do > + switch="-std=gnu++${alternative}" > + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) > + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, > + $cachevar, > + [ac_save_CXX="$CXX" > + CXX="$CXX $switch" > + > AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], > + [eval $cachevar=yes], > + [eval $cachevar=no]) > + CXX="$ac_save_CXX"]) > + if eval test x\$$cachevar = xyes; then > + CXX="$CXX $switch" > + if test -n "$CXXCPP" ; then > + CXXCPP="$CXXCPP $switch" > + fi > + ac_success=yes > + break > + fi > + done > + fi]) > + > + m4_if([$2], [ext], [], [dnl > + if test x$ac_success = xno; then > + dnl HP's aCC needs +std=c++11 according to: > + dnl > http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf > + dnl Cray's crayCC needs "-h std=c++11" > + for alternative in ${ax_cxx_compile_alternatives}; do > + for switch in -std=c++${alternative} +std=c++${alternative} "-h > std=c++${alternative}"; do > + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) > + AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, > + $cachevar, > + [ac_save_CXX="$CXX" > + CXX="$CXX $switch" > + > AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], > + [eval $cachevar=yes], > + [eval $cachevar=no]) > + CXX="$ac_save_CXX"]) > + if eval test x\$$cachevar = xyes; then > + CXX="$CXX $switch" > + if test -n "$CXXCPP" ; then > + CXXCPP="$CXXCPP $switch" > + fi > + ac_success=yes > + break > + fi > + done > + if test x$ac_success = xyes; then > + break > + fi > + done > + fi]) > + AC_LANG_POP([C++]) > + if test x$ax_cxx_compile_cxx$1_required = xtrue; then > + if test x$ac_success = xno; then > + AC_MSG_ERROR([*** A compiler with support for C++$1 language features > is required.]) > + fi > + fi > + if test x$ac_success = xno; then > + HAVE_CXX$1=0 > + AC_MSG_NOTICE([No compiler with C++$1 support was found]) > + else > + HAVE_CXX$1=1 > + AC_DEFINE(HAVE_CXX$1,1, > + [define if the compiler supports basic C++$1 syntax]) > + fi > + AC_SUBST(HAVE_CXX$1) > + m4_if([$1], [17], [AC_MSG_WARN([C++17 is not yet standardized, so the > checks may change in incompatible ways anytime])]) > +]) > + > + > +dnl Test body for checking C++11 support > + > +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], > + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 > +) > + > + > +dnl Test body for checking C++14 support > + > +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], > + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 > + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 > +) > + > +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], > + _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 > + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 > + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 > +) > + > +dnl Tests for new features in C++11 > + > +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ > + > +// If the compiler admits that it is not ready for C++11, why torture it? > +// Hopefully, this will speed up the test. > + > +#ifndef __cplusplus > + > +#error "This is not a C++ compiler" > + > +#elif __cplusplus < 201103L > + > +#error "This is not a C++11 compiler" > + > +#else > + > +namespace cxx11 > +{ > + > + namespace test_static_assert > + { > + > + template <typename T> > + struct check > + { > + static_assert(sizeof(int) <= sizeof(T), "not big enough"); > + }; > + > + } > + > + namespace test_final_override > + { > + > + struct Base > + { > + virtual void f() {} > + }; > + > + struct Derived : public Base > + { > + virtual void f() override {} > + }; > + > + } > + > + namespace test_double_right_angle_brackets > + { > + > + template < typename T > > + struct check {}; > + > + typedef check<void> single_type; > + typedef check<check<void>> double_type; > + typedef check<check<check<void>>> triple_type; > + typedef check<check<check<check<void>>>> quadruple_type; > + > + } > + > + namespace test_decltype > + { > + > + int > + f() > + { > + int a = 1; > + decltype(a) b = 2; > + return a + b; > + } > + > + } > + > + namespace test_type_deduction > + { > + > + template < typename T1, typename T2 > > + struct is_same > + { > + static const bool value = false; > + }; > + > + template < typename T > > + struct is_same<T, T> > + { > + static const bool value = true; > + }; > + > + template < typename T1, typename T2 > > + auto > + add(T1 a1, T2 a2) -> decltype(a1 + a2) > + { > + return a1 + a2; > + } > + > + int > + test(const int c, volatile int v) > + { > + static_assert(is_same<int, decltype(0)>::value == true, ""); > + static_assert(is_same<int, decltype(c)>::value == false, ""); > + static_assert(is_same<int, decltype(v)>::value == false, ""); > + auto ac = c; > + auto av = v; > + auto sumi = ac + av + 'x'; > + auto sumf = ac + av + 1.0; > + static_assert(is_same<int, decltype(ac)>::value == true, ""); > + static_assert(is_same<int, decltype(av)>::value == true, ""); > + static_assert(is_same<int, decltype(sumi)>::value == true, ""); > + static_assert(is_same<int, decltype(sumf)>::value == false, ""); > + static_assert(is_same<int, decltype(add(c, v))>::value == true, ""); > + return (sumf > 0.0) ? sumi : add(c, v); > + } > + > + } > + > + namespace test_noexcept > + { > + > + int f() { return 0; } > + int g() noexcept { return 0; } > + > + static_assert(noexcept(f()) == false, ""); > + static_assert(noexcept(g()) == true, ""); > + > + } > + > + namespace test_constexpr > + { > + > + template < typename CharT > > + unsigned long constexpr > + strlen_c_r(const CharT *const s, const unsigned long acc) noexcept > + { > + return *s ? strlen_c_r(s + 1, acc + 1) : acc; > + } > + > + template < typename CharT > > + unsigned long constexpr > + strlen_c(const CharT *const s) noexcept > + { > + return strlen_c_r(s, 0UL); > + } > + > + static_assert(strlen_c("") == 0UL, ""); > + static_assert(strlen_c("1") == 1UL, ""); > + static_assert(strlen_c("example") == 7UL, ""); > + static_assert(strlen_c("another\0example") == 7UL, ""); > + > + } > + > + namespace test_rvalue_references > + { > + > + template < int N > > + struct answer > + { > + static constexpr int value = N; > + }; > + > + answer<1> f(int&) { return answer<1>(); } > + answer<2> f(const int&) { return answer<2>(); } > + answer<3> f(int&&) { return answer<3>(); } > + > + void > + test() > + { > + int i = 0; > + const int c = 0; > + static_assert(decltype(f(i))::value == 1, ""); > + static_assert(decltype(f(c))::value == 2, ""); > + static_assert(decltype(f(0))::value == 3, ""); > + } > + > + } > + > + namespace test_uniform_initialization > + { > + > + struct test > + { > + static const int zero {}; > + static const int one {1}; > + }; > + > + static_assert(test::zero == 0, ""); > + static_assert(test::one == 1, ""); > + > + } > + > + namespace test_lambdas > + { > + > + void > + test1() > + { > + auto lambda1 = [](){}; > + auto lambda2 = lambda1; > + lambda1(); > + lambda2(); > + } > + > + int > + test2() > + { > + auto a = [](int i, int j){ return i + j; }(1, 2); > + auto b = []() -> int { return '0'; }(); > + auto c = [=](){ return a + b; }(); > + auto d = [&](){ return c; }(); > + auto e = [a, &b](int x) mutable { > + const auto identity = [](int y){ return y; }; > + for (auto i = 0; i < a; ++i) > + a += b--; > + return x + identity(a + b); > + }(0); > + return a + b + c + d + e; > + } > + > + int > + test3() > + { > + const auto nullary = [](){ return 0; }; > + const auto unary = [](int x){ return x; }; > + using nullary_t = decltype(nullary); > + using unary_t = decltype(unary); > + const auto higher1st = [](nullary_t f){ return f(); }; > + const auto higher2nd = [unary](nullary_t f1){ > + return [unary, f1](unary_t f2){ return f2(unary(f1())); }; > + }; > + return higher1st(nullary) + higher2nd(nullary)(unary); > + } > + > + } > + > + namespace test_variadic_templates > + { > + > + template <int...> > + struct sum; > + > + template <int N0, int... N1toN> > + struct sum<N0, N1toN...> > + { > + static constexpr auto value = N0 + sum<N1toN...>::value; > + }; > + > + template <> > + struct sum<> > + { > + static constexpr auto value = 0; > + }; > + > + static_assert(sum<>::value == 0, ""); > + static_assert(sum<1>::value == 1, ""); > + static_assert(sum<23>::value == 23, ""); > + static_assert(sum<1, 2>::value == 3, ""); > + static_assert(sum<5, 5, 11>::value == 21, ""); > + static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); > + > + } > + > + // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae > + // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function > + // because of this. > + namespace test_template_alias_sfinae > + { > + > + struct foo {}; > + > + template<typename T> > + using member = typename T::member_type; > + > + template<typename T> > + void func(...) {} > + > + template<typename T> > + void func(member<T>*) {} > + > + void test(); > + > + void test() { func<foo>(0); } > + > + } > + > +} // namespace cxx11 > + > +#endif // __cplusplus >= 201103L > + > +]]) > + > + > +dnl Tests for new features in C++14 > + > +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ > + > +// If the compiler admits that it is not ready for C++14, why torture it? > +// Hopefully, this will speed up the test. > + > +#ifndef __cplusplus > + > +#error "This is not a C++ compiler" > + > +#elif __cplusplus < 201402L > + > +#error "This is not a C++14 compiler" > + > +#else > + > +namespace cxx14 > +{ > + > + namespace test_polymorphic_lambdas > + { > + > + int > + test() > + { > + const auto lambda = [](auto&&... args){ > + const auto istiny = [](auto x){ > + return (sizeof(x) == 1UL) ? 1 : 0; > + }; > + const int aretiny[] = { istiny(args)... }; > + return aretiny[0]; > + }; > + return lambda(1, 1L, 1.0f, '1'); > + } > + > + } > + > + namespace test_binary_literals > + { > + > + constexpr auto ivii = 0b0000000000101010; > + static_assert(ivii == 42, "wrong value"); > + > + } > + > + namespace test_generalized_constexpr > + { > + > + template < typename CharT > > + constexpr unsigned long > + strlen_c(const CharT *const s) noexcept > + { > + auto length = 0UL; > + for (auto p = s; *p; ++p) > + ++length; > + return length; > + } > + > + static_assert(strlen_c("") == 0UL, ""); > + static_assert(strlen_c("x") == 1UL, ""); > + static_assert(strlen_c("test") == 4UL, ""); > + static_assert(strlen_c("another\0test") == 7UL, ""); > + > + } > + > + namespace test_lambda_init_capture > + { > + > + int > + test() > + { > + auto x = 0; > + const auto lambda1 = [a = x](int b){ return a + b; }; > + const auto lambda2 = [a = lambda1(x)](){ return a; }; > + return lambda2(); > + } > + > + } > + > + namespace test_digit_separators > + { > + > + constexpr auto ten_million = 100'000'000; > + static_assert(ten_million == 100000000, ""); > + > + } > + > + namespace test_return_type_deduction > + { > + > + auto f(int& x) { return x; } > + decltype(auto) g(int& x) { return x; } > + > + template < typename T1, typename T2 > > + struct is_same > + { > + static constexpr auto value = false; > + }; > + > + template < typename T > > + struct is_same<T, T> > + { > + static constexpr auto value = true; > + }; > + > + int > + test() > + { > + auto x = 0; > + static_assert(is_same<int, decltype(f(x))>::value, ""); > + static_assert(is_same<int&, decltype(g(x))>::value, ""); > + return x; > + } > + > + } > + > +} // namespace cxx14 > + > +#endif // __cplusplus >= 201402L > + > +]]) > + > + > +dnl Tests for new features in C++17 > + > +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ > + > +// If the compiler admits that it is not ready for C++17, why torture it? > +// Hopefully, this will speed up the test. > + > +#ifndef __cplusplus > + > +#error "This is not a C++ compiler" > + > +#elif __cplusplus <= 201402L > + > +#error "This is not a C++17 compiler" > + > +#else > + > +#if defined(__clang__) > + #define REALLY_CLANG > +#else > + #if defined(__GNUC__) > + #define REALLY_GCC > + #endif > +#endif > + > +#include <initializer_list> > +#include <utility> > +#include <type_traits> > + > +namespace cxx17 > +{ > + > +#if !defined(REALLY_CLANG) > + namespace test_constexpr_lambdas > + { > + > + // TODO: test it with clang++ from git > + > + constexpr int foo = [](){return 42;}(); > + > + } > +#endif // !defined(REALLY_CLANG) > + > + namespace test::nested_namespace::definitions > + { > + > + } > + > + namespace test_fold_expression > + { > + > + template<typename... Args> > + int multiply(Args... args) > + { > + return (args * ... * 1); > + } > + > + template<typename... Args> > + bool all(Args... args) > + { > + return (args && ...); > + } > + > + } > + > + namespace test_extended_static_assert > + { > + > + static_assert (true); > + > + } > + > + namespace test_auto_brace_init_list > + { > + > + auto foo = {5}; > + auto bar {5}; > + > + static_assert(std::is_same<std::initializer_list<int>, > decltype(foo)>::value); > + static_assert(std::is_same<int, decltype(bar)>::value); > + } > + > + namespace test_typename_in_template_template_parameter > + { > + > + template<template<typename> typename X> struct D; > + > + } > + > + namespace test_fallthrough_nodiscard_maybe_unused_attributes > + { > + > + int f1() > + { > + return 42; > + } > + > + [[nodiscard]] int f2() > + { > + [[maybe_unused]] auto unused = f1(); > + > + switch (f1()) > + { > + case 17: > + f1(); > + [[fallthrough]]; > + case 42: > + f1(); > + } > + return f1(); > + } > + > + } > + > + namespace test_extended_aggregate_initialization > + { > + > + struct base1 > + { > + int b1, b2 = 42; > + }; > + > + struct base2 > + { > + base2() { > + b3 = 42; > + } > + int b3; > + }; > + > + struct derived : base1, base2 > + { > + int d; > + }; > + > + derived d1 {{1, 2}, {}, 4}; // full initialization > + derived d2 {{}, {}, 4}; // value-initialized bases > + > + } > + > + namespace test_general_range_based_for_loop > + { > + > + struct iter > + { > + int i; > + > + int& operator* () > + { > + return i; > + } > + > + const int& operator* () const > + { > + return i; > + } > + > + iter& operator++() > + { > + ++i; > + return *this; > + } > + }; > + > + struct sentinel > + { > + int i; > + }; > + > + bool operator== (const iter& i, const sentinel& s) > + { > + return i.i == s.i; > + } > + > + bool operator!= (const iter& i, const sentinel& s) > + { > + return !(i == s); > + } > + > + struct range > + { > + iter begin() const > + { > + return {0}; > + } > + > + sentinel end() const > + { > + return {5}; > + } > + }; > + > + void f() > + { > + range r {}; > + > + for (auto i : r) > + { > + [[maybe_unused]] auto v = i; > + } > + } > + > + } > + > + namespace test_lambda_capture_asterisk_this_by_value > + { > + > + struct t > + { > + int i; > + int foo() > + { > + return [*this]() > + { > + return i; > + }(); > + } > + }; > + > + } > + > + namespace test_enum_class_construction > + { > + > + enum class byte : unsigned char > + {}; > + > + byte foo {42}; > + > + } > + > + namespace test_constexpr_if > + { > + > + template <bool cond> > + int f () > + { > + if constexpr(cond) > + { > + return 13; > + } > + else > + { > + return 42; > + } > + } > + > + } > + > + namespace test_selection_statement_with_initializer > + { > + > + int f() > + { > + return 13; > + } > + > + int f2() > + { > + if (auto i = f(); i > 0) > + { > + return 3; > + } > + > + switch (auto i = f(); i + 4) > + { > + case 17: > + return 2; > + > + default: > + return 1; > + } > + } > + > + } > + > +#if !defined(REALLY_CLANG) > + namespace test_template_argument_deduction_for_class_templates > + { > + > + // TODO: test it with clang++ from git > + > + template <typename T1, typename T2> > + struct pair > + { > + pair (T1 p1, T2 p2) > + : m1 {p1}, > + m2 {p2} > + {} > + > + T1 m1; > + T2 m2; > + }; > + > + void f() > + { > + [[maybe_unused]] auto p = pair{13, 42u}; > + } > + > + } > +#endif // !defined(REALLY_CLANG) > + > + namespace test_non_type_auto_template_parameters > + { > + > + template <auto n> > + struct B > + {}; > + > + B<5> b1; > + B<'a'> b2; > + > + } > + > +#if !defined(REALLY_CLANG) > + namespace test_structured_bindings > + { > + > + // TODO: test it with clang++ from git > + > + int arr[2] = { 1, 2 }; > + std::pair<int, int> pr = { 1, 2 }; > + > + auto f1() -> int(&)[2] > + { > + return arr; > + } > + > + auto f2() -> std::pair<int, int>& > + { > + return pr; > + } > + > + struct S > + { > + int x1 : 2; > + volatile double y1; > + }; > + > + S f3() > + { > + return {}; > + } > + > + auto [ x1, y1 ] = f1(); > + auto& [ xr1, yr1 ] = f1(); > + auto [ x2, y2 ] = f2(); > + auto& [ xr2, yr2 ] = f2(); > + const auto [ x3, y3 ] = f3(); > + > + } > +#endif // !defined(REALLY_CLANG) > + > +#if !defined(REALLY_CLANG) > + namespace test_exception_spec_type_system > + { > + > + // TODO: test it with clang++ from git > + > + struct Good {}; > + struct Bad {}; > + > + void g1() noexcept; > + void g2(); > + > + template<typename T> > + Bad > + f(T*, T*); > + > + template<typename T1, typename T2> > + Good > + f(T1*, T2*); > + > + static_assert (std::is_same_v<Good, decltype(f(g1, g2))>); > + > + } > +#endif // !defined(REALLY_CLANG) > + > + namespace test_inline_variables > + { > + > + template<class T> void f(T) > + {} > + > + template<class T> inline T g(T) > + { > + return T{}; > + } > + > + template<> inline void f<>(int) > + {} > + > + template<> int g<>(int) > + { > + return 5; > + } > + > + } > + > +} // namespace cxx17 > + > +#endif // __cplusplus <= 201402L > + > +]]) > diff --git a/m4/openvswitch.m4 b/m4/openvswitch.m4 > index 648750ab5ad9..00ffad35f6b0 100644 > --- a/m4/openvswitch.m4 > +++ b/m4/openvswitch.m4 > @@ -620,3 +620,19 @@ AC_DEFUN([OVS_LIBTOOL_VERSIONS], > AC_MSG_RESULT([libX-$OVS_MAJOR.$OVS_MINOR.so.$LT_CURRENT.0.$OVS_MICRO)]) > AC_SUBST(OVS_LTINFO) > ]) > + > +dnl OVS does not use C++ itself, but it provides public header files > +dnl that a C++ compiler should accept, so when --enable-Werror is in > +dnl effect and a C++ compiler is available, we enable building a C++ > +dnl source file that #includes all the public headers, as a way to > +dnl ensure that they are acceptable as C++. > +AC_DEFUN([OVS_CHECK_CXX], > + [AC_REQUIRE([AC_PROG_CXX]) > + AC_REQUIRE([OVS_ENABLE_WERROR]) > + AX_CXX_COMPILE_STDCXX([11], [], [optional]) > + if test $enable_Werror = yes && test $HAVE_CXX11 = 1; then > + enable_cxx=: > + else > + enable_cxx=false > + fi > + AM_CONDITIONAL([HAVE_CXX], [$enable_cxx])]) > -- > 2.10.2 -- Russell Bryant _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
