Skip to content
Snippets Groups Projects
Commit 1410d4a9 authored by Christian Engwer's avatar Christian Engwer
Browse files

Merge branch 'feature/assert-and-return' into 'master'

Add macro DUNE_ASSERT_AND_RETURN

This is an alternative to !128.

In C++11 and with not fully C++14 compliant compilers `constexpr` functions
can only have a return statement. This prevents the use of `assert()` inside
of `constexpr` functions. This macro can be used as a workaround like this:

```c++
  constexpr auto foo(int a, int b, x)
  {
    return DUNE_ASSERT_AND_RETURN(a<b, x);
  }
```

For `NDEBUG` there is no penalty. Otherwise there are two options:
* In a non-`constexpr` context an `assert()` will fail if the condition
  is not matched. The error message will be slightly different from a
  classic assertion.
* In a `constexpr` context the `assert()` branch will be ignored if the
  is condition is matched. Otherwise this will lead to a compile error
  (like `static_assert`) because the branch using `assert()` is not `constexpr`.

See merge request !142
parents 68f429a9 63c0a712
No related branches found
No related tags found
2 merge requests!212Fix link to build system doc,!142Add macro DUNE_ASSERT_AND_RETURN
Pipeline #
......@@ -27,6 +27,7 @@ install(FILES
alignment.hh
array.hh
arraylist.hh
assertandreturn.hh
bartonnackmanifcheck.hh
bigunsignedint.hh
binaryfunctions.hh
......
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_COMMON_ASSERTANDRETURN_HH
#define DUNE_COMMON_ASSERTANDRETURN_HH
#include <cassert>
// The macro DUNE_ASSERT_AND_RETURN can be used as expression in the return
// statement of a constexpr function to have assert() and constexpr at the
// same time. It first uses assert for the condition given by the first argument
// and then returns the value of the second argument.
#ifdef NDEBUG
#define DUNE_ASSERT_AND_RETURN(C,X) X
#else
#define DUNE_ASSERT_AND_RETURN(C,X) (!(C) ? throw [&](){assert(!#C);return 0;}() : 0), X
#endif
#endif // DUNE_COMMON_ASSERTANDRETURN_HH
......@@ -10,6 +10,7 @@
#include <dune/common/typeutilities.hh>
#include <dune/common/fvector.hh>
#include <dune/common/indices.hh>
#include <dune/common/assertandreturn.hh>
......@@ -197,10 +198,9 @@ namespace Impl {
// constexpr the function body can only contain a return
// statement and no assertion before this.
template<class Begin, class End>
auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
constexpr auto integralRange(const Begin& begin, const End& end, const PriorityTag<0>&)
{
assert(begin <= end);
return Impl::DynamicIntegralRange<End>(begin, end);
return DUNE_ASSERT_AND_RETURN(begin<=end, Impl::DynamicIntegralRange<End>(begin, end));
}
} // namespace Impl
......
......@@ -2,6 +2,18 @@ dune_add_test(SOURCES arraylisttest.cc)
dune_add_test(SOURCES arraytest.cc)
dune_add_test(SOURCES assertandreturntest.cc
LINK_LIBRARIES dunecommon)
dune_add_test(NAME assertandreturntest_compiletime_fail
SOURCES assertandreturntest.cc
LINK_LIBRARIES dunecommon
COMPILE_DEFINITIONS "TEST_COMPILETIME_FAIL"
EXPECT_COMPILE_FAIL)
dune_add_test(NAME assertandreturntest_ndebug
SOURCES assertandreturntest.cc
LINK_LIBRARIES dunecommon
COMPILE_DEFINITIONS "TEST_NDEBUG")
dune_add_test(SOURCES bigunsignedinttest.cc
LINK_LIBRARIES dunecommon)
......
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#include <config.h>
#ifdef TEST_NDEBUG
#define NDEBUG TEST_NDEBUG
#else
#undef NDDEBUG
#endif
#include <cassert>
#include <dune/common/parallel/mpihelper.hh>
#include <dune/common/exceptions.hh>
#include <dune/common/assertandreturn.hh>
struct Foo
{
static constexpr auto lessAndReturn(int a, int b, int x)
{
return DUNE_ASSERT_AND_RETURN(a<b, x);
}
};
int main ( int argc, char **argv )
try
{
using namespace Dune;
MPIHelper::instance(argc, argv);
// This should not fail since 0<2
if (Foo::lessAndReturn(0,2,3) != 3)
DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in dynamic context");
// This should not fail since 0<2
if (std::integral_constant<int, Foo::lessAndReturn(0,2,3)>::value != 3)
DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in constexpr context");
// If EXPECT_FAIL would work with failing assertions,
// we could test if the assertion is triggered with
// a target
//
// dune_add_test(NAME assertandreturntest_runtime_fail
// SOURCES assertandreturntest.cc
// LINK_LIBRARIES dunecommon
// COMPILE_DEFINITIONS "TEST_RUNTIME_FAIL"
// EXPECT_FAIL)
//
// and the following code:
#ifdef TEST_RUNTIME_FAIL
// This should fail at runtime because 0>-3
if (Foo::lessAndReturn(0,-1,3) != 3)
DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in dynamic context");
#endif
#ifdef TEST_COMPILETIME_FAIL
// This should fail at compile time because 0>-3
if (std::integral_constant<int, Foo::lessAndReturn(0,-1,3)>::value != 3)
DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in constexpr context");
#endif
#ifdef TEST_NDEBUG
// This should not fail because NDEBUG is set
if (Foo::lessAndReturn(0,-1,3) != 3)
DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in dynamic context");
// This should not fail because NDEBUG is set
if (std::integral_constant<int, Foo::lessAndReturn(0,-1,3)>::value != 3)
DUNE_THROW(Dune::Exception, "DUNE_ASSERT_AND_RETURN returned incorrect value in constexpr context");
#endif
return 0;
}
catch( Dune::Exception &e )
{
std::cerr << "Dune reported error: " << e << std::endl;
return 1;
}
catch(...)
{
std::cerr << "Unknown exception thrown!" << std::endl;
return 1;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment