Skip to content

Commit

Permalink
Make version with no-exception support (#27)
Browse files Browse the repository at this point in the history
May need additional changes.
  • Loading branch information
martinmoene committed Nov 25, 2019
1 parent 96ae9ec commit 857ee52
Show file tree
Hide file tree
Showing 7 changed files with 258 additions and 5 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ Define this to `nsel_EXPECTED_STD` to select `std::expected` as `nonstd::expecte
-D<b>nsel\_P0323R</b>=7 *(default)*
Define this to the proposal revision number to control the presence and behavior of features (see tables). Default is 7 for the latest revision.
#### Disable exceptions
-D<b>nsel\_CONFIG\_NO\_EXCEPTIONS</b>=0
Define this to 1 if you want to compile without exceptions. If not defined, the header tries and detect if exceptions have been disabled (e.g. via `-fno-exceptions`). Default is undefined.
#### Enable compilation errors
\-D<b>nsel\_CONFIG\_CONFIRMS\_COMPILATION\_ERRORS</b>=0
Define this macro to 1 to experience the by-design compile-time errors of the library in the test suite. Default is 0.
Expand Down
59 changes: 55 additions & 4 deletions include/nonstd/expected.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,11 +203,20 @@ namespace nonstd {
#include <initializer_list>
#include <memory>
#include <new>
#include <stdexcept>
#include <system_error>
#include <type_traits>
#include <utility>

// additional includes:

#if nsel_CONFIG_NO_EXCEPTIONS
// already included: <cassert>
#else
# include <stdexcept>
#endif

// C++ feature usage:

#if nsel_CPP11_OR_GREATER
# define nsel_constexpr constexpr
#else
Expand Down Expand Up @@ -433,7 +442,7 @@ class storage_t_impl
storage_t_impl() {}
~storage_t_impl() {}

explicit storage_t_impl( bool has_value )
explicit storage_t_impl( bool has_value )
: m_has_value( has_value )
{}

Expand Down Expand Up @@ -627,7 +636,7 @@ struct storage_t_impl<void, E>
return std::move( m_error );
}

bool has_value() const
bool has_value() const
{
return m_has_value;
}
Expand Down Expand Up @@ -992,7 +1001,8 @@ unexpected_type( E ) -> unexpected_type< E >;

/// class unexpected_type, std::exception_ptr specialization (P0323R2)

#if nsel_P0323R <= 2
#if !nsel_CONFIG_NO_EXCEPTIONS
#if nsel_P0323R <= 2

// TODO: Should expected be specialized for particular E types such as exception_ptr and how?
// See p0323r7 2.1. Ergonomics, http://wg21.link/p0323
Expand Down Expand Up @@ -1034,6 +1044,7 @@ class unexpected_type< std::exception_ptr >
};

#endif // nsel_P0323R
#endif // !nsel_CONFIG_NO_EXCEPTIONS

/// x.x.4, Unexpected equality operators

Expand Down Expand Up @@ -1166,6 +1177,8 @@ class bad_expected_access< void > : public std::exception

/// x.x.6 bad_expected_access: expected access error

#if !nsel_CONFIG_NO_EXCEPTIONS

template< typename E >
class bad_expected_access : public bad_expected_access< void >
{
Expand Down Expand Up @@ -1209,6 +1222,8 @@ class bad_expected_access : public bad_expected_access< void >
error_type m_error;
};

#endif // nsel_CONFIG_NO_EXCEPTIONS

/// x.x.8 unexpect tag, in_place_unexpected tag: construct an error

struct unexpect_t{};
Expand All @@ -1219,6 +1234,40 @@ nsel_inline17 constexpr unexpect_t in_place_unexpected{};

/// class error_traits

#if nsel_CONFIG_NO_EXCEPTIONS

namespace detail {
bool text( char const * /*text*/ ) { return true; }
}
template< typename Error >
struct error_traits
{
static void rethrow( Error const & /*e*/ )
{
assert( false && detail::text("throw bad_expected_access<Error>{ e };") );
}
};

template<>
struct error_traits< std::exception_ptr >
{
static void rethrow( std::exception_ptr const & /*e*/ )
{
assert( false && detail::text("throw bad_expected_access<std::exception_ptr>{ e };") );
}
};

template<>
struct error_traits< std::error_code >
{
static void rethrow( std::error_code const & /*e*/ )
{
assert( false && detail::text("throw std::system_error( e );") );
}
};

#else // nsel_CONFIG_NO_EXCEPTIONS

template< typename Error >
struct error_traits
{
Expand Down Expand Up @@ -1246,6 +1295,8 @@ struct error_traits< std::error_code >
}
};

#endif // nsel_CONFIG_NO_EXCEPTIONS

} // namespace expected_lite

// provide nonstd::unexpected_type:
Expand Down
2 changes: 1 addition & 1 deletion test/expected-main.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ CASE( "any configuration" "[.expected][.config]" )
{
expected_PRESENT( nsel_HAVE_STD_EXPECTED );
expected_PRESENT( nsel_USES_STD_EXPECTED );
expected_PRESENT( nsel_CONFIG_SELECT_EXPECTED );
expected_PRESENT( nsel_EXPECTED_DEFAULT );
expected_PRESENT( nsel_EXPECTED_NONSTD );
expected_PRESENT( nsel_EXPECTED_STD );
expected_PRESENT( nsel_CONFIG_SELECT_EXPECTED );
expected_PRESENT( nsel_CONFIG_NO_EXCEPTIONS );
expected_PRESENT( nsel_CPLUSPLUS );
}

Expand Down
31 changes: 31 additions & 0 deletions test/expected-noexcept.t.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright (c) 2016-2019 Martin Moene
//
// https://github.com/martinmoene/expected-lite
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include "nonstd/expected.hpp"

template< typename T >
void use( T const & /*x*/) {}

int main()
{
nonstd::expected<int, char> e;
nonstd::unexpected_type<int> ut(7);

use(e);
use(ut);

#if nsel_CPP17_OR_GREATER && nsel_COMPILER_MSVC_VERSION > 141
nonstd::unexpected<int> u(3); u;
use(u);
#endif

nonstd::expected<int, char> eu( nonstd:: make_unexpected('a') );

return eu.value();
}

// end of file
59 changes: 59 additions & 0 deletions test/t-noexcept.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
@echo off & setlocal enableextensions enabledelayedexpansion
::
:: t.bat - compile & run tests (MSVC).
::

set unit=expected

:: if no std is given, use compiler default

set std=%1
if not "%std%"=="" set std=-std:%std%

call :CompilerVersion version
echo VC%version%: %args%

set UCAP=%unit%
call :toupper UCAP

set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT
::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD
::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD

set unit_config=

set msvc_defines=^
-Dlest_FEATURE_AUTO_REGISTER=1 ^
-D_CRT_SECURE_NO_WARNINGS ^
-D_SCL_SECURE_NO_WARNINGS ^
-Dnsel_CONFIG_NO_EXCEPTIONS=1

set CppCoreCheckInclude=%VCINSTALLDIR%\Auxiliary\VS\include

:: -EHsc
cl -W3 %std% %unit_select% %unit_config% %msvc_defines% -I"%CppCoreCheckInclude%" -I../include %unit%-noexcept.t.cpp && %unit%-noexcept.t.exe
endlocal & goto :EOF

:: subroutines:

:CompilerVersion version
@echo off & setlocal enableextensions
set tmpprogram=_getcompilerversion.tmp
set tmpsource=%tmpprogram%.c

echo #include ^<stdio.h^> >%tmpsource%
echo int main(){printf("%%d\n",_MSC_VER);} >>%tmpsource%

cl /nologo %tmpsource% >nul
for /f %%x in ('%tmpprogram%') do set version=%%x
del %tmpprogram%.* >nul
set offset=0
if %version% LSS 1900 set /a offset=1
set /a version="version / 10 - 10 * ( 5 + offset )"
endlocal & set %1=%version%& goto :EOF

:: toupper; makes use of the fact that string
:: replacement (via SET) is not case sensitive
:toupper
for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L!
goto :EOF
53 changes: 53 additions & 0 deletions test/tc-noexcept.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@echo off & setlocal enableextensions enabledelayedexpansion
::
:: tc.bat - compile & run tests (clang).
::

set unit=expected

:: if no std is given, use c++14

set std=%1
if "%std%"=="" set std=c++14

set clang=clang

call :CompilerVersion version
echo %clang% %version%: %std%

set UCAP=%unit%
call :toupper UCAP

set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT
::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD
::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD

set unit_config=

rem -flto / -fwhole-program
set optflags=-O2 -fno-exceptions
set warnflags=-Wall -Wextra -Wpedantic -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-padded -Wno-missing-noreturn -Wno-documentation-unknown-command -Wno-documentation-deprecated-sync -Wno-documentation -Wno-weak-vtables -Wno-missing-prototypes -Wno-missing-variable-declarations -Wno-exit-time-destructors -Wno-global-constructors

"%clang%" -m32 -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -Dlest_FEATURE_AUTO_REGISTER=1 -fms-compatibility-version=19.00 -isystem "%VCInstallDir%include" -isystem "%WindowsSdkDir_71A%include" -I../include -o %unit%-main.t.exe %unit%-noexcept.t.cpp && %unit%-noexcept.t.exe
endlocal & goto :EOF

:: subroutines:

:CompilerVersion version
echo off & setlocal enableextensions
set tmpprogram=_getcompilerversion.tmp
set tmpsource=%tmpprogram%.c

echo #include ^<stdio.h^> > %tmpsource%
echo int main(){printf("%%d.%%d.%%d\n",__clang_major__,__clang_minor__,__clang_patchlevel__);} >> %tmpsource%

"%clang%" -m32 -o %tmpprogram% %tmpsource% >nul
for /f %%x in ('%tmpprogram%') do set version=%%x
del %tmpprogram%.* >nul
endlocal & set %1=%version%& goto :EOF

:: toupper; makes use of the fact that string
:: replacement (via SET) is not case sensitive
:toupper
for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L!
goto :EOF
55 changes: 55 additions & 0 deletions test/tg-noexcept.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@echo off & setlocal enableextensions enabledelayedexpansion
::
:: tg.bat - compile & run tests (GNUC).
::

set unit=expected

:: if no std is given, use c++11

set std=%1
set args=%2 %3 %4 %5 %6 %7 %8 %9
if "%1" == "" set std=c++11

set gpp=g++

call :CompilerVersion version
echo %gpp% %version%: %std% %args%

set UCAP=%unit%
call :toupper UCAP

set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_DEFAULT
::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_NONSTD
::set unit_select=-D%unit%_CONFIG_SELECT_%UCAP%=%unit%_%UCAP%_STD

set unit_config=-Dnsel_CONFIG_NO_EXCEPTIONS=1

rem -flto / -fwhole-program
set optflags=-O2 -fno-exceptions
set warnflags=-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wno-padded -Wno-missing-noreturn

%gpp% -std=%std% %optflags% %warnflags% %unit_select% %unit_config% -o %unit%-main.t.exe -Dlest_FEATURE_AUTO_REGISTER=1 -I../include %unit%-noexcept.t.cpp && %unit%-main.t.exe

endlocal & goto :EOF

:: subroutines:

:CompilerVersion version
echo off & setlocal enableextensions
set tmpprogram=_getcompilerversion.tmp
set tmpsource=%tmpprogram%.c

echo #include ^<stdio.h^> > %tmpsource%
echo int main(){printf("%%d.%%d.%%d\n",__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__);} >> %tmpsource%

%gpp% -o %tmpprogram% %tmpsource% >nul
for /f %%x in ('%tmpprogram%') do set version=%%x
del %tmpprogram%.* >nul
endlocal & set %1=%version%& goto :EOF

:: toupper; makes use of the fact that string
:: replacement (via SET) is not case sensitive
:toupper
for %%L IN (A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) DO SET %1=!%1:%%L=%%L!
goto :EOF

0 comments on commit 857ee52

Please sign in to comment.