/* Self tests for offset types for GDB, the GNU debugger. Copyright (C) 2017-2018 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "defs.h" #include "selftest.h" #include "common/offset-type.h" #include "common/underlying.h" #include "common/valid-expr.h" namespace selftests { namespace offset_type { DEFINE_OFFSET_TYPE (off_A, unsigned int); DEFINE_OFFSET_TYPE (off_B, unsigned int); /* First, compile-time tests that: - make sure that incorrect operations with mismatching types are caught at compile time. - make sure that the same operations but involving the right types do compile and that they return the correct type. */ #define CHECK_VALID(VALID, EXPR_TYPE, EXPR) \ CHECK_VALID_EXPR_2 (off_A, off_B, VALID, EXPR_TYPE, EXPR) off_A lval_a {}; off_B lval_b {}; using undrl = std::underlying_type::type; /* Offset +/- underlying. */ CHECK_VALID (true, off_A, off_A {} + undrl {}); CHECK_VALID (true, off_A, off_A {} - undrl {}); CHECK_VALID (true, off_A, undrl {} + off_A {}); CHECK_VALID (true, off_A, undrl {} - off_A {}); /* Add offset types. Both same and different. */ CHECK_VALID (false, void, off_A {} + off_A {}); CHECK_VALID (false, void, off_A {} + off_B {}); /* Subtract offset types. Both same and different. */ CHECK_VALID (false, void, off_B {} - off_A {}); CHECK_VALID (true, undrl, off_A {} - off_A {}); /* Add/assign offset types. Both same and different. */ CHECK_VALID (false, void, lval_a += off_A {}); CHECK_VALID (false, void, lval_a += off_B {}); CHECK_VALID (false, void, lval_a -= off_A {}); CHECK_VALID (false, void, lval_a -= off_B {}); /* operator OP+= (offset, underlying), lvalue ref on the lhs. */ CHECK_VALID (true, off_A&, lval_a += undrl {}); CHECK_VALID (true, off_A&, lval_a -= undrl {}); /* operator OP+= (offset, underlying), rvalue ref on the lhs. */ CHECK_VALID (false, void, off_A {} += undrl {}); CHECK_VALID (false, void, off_A {} -= undrl {}); /* Rel ops, with same type. */ CHECK_VALID (true, bool, off_A {} < off_A {}); CHECK_VALID (true, bool, off_A {} > off_A {}); CHECK_VALID (true, bool, off_A {} <= off_A {}); CHECK_VALID (true, bool, off_A {} >= off_A {}); /* Rel ops, with unrelated offset types. */ CHECK_VALID (false, void, off_A {} < off_B {}); CHECK_VALID (false, void, off_A {} > off_B {}); CHECK_VALID (false, void, off_A {} <= off_B {}); CHECK_VALID (false, void, off_A {} >= off_B {}); /* Rel ops, with unrelated types. */ CHECK_VALID (false, void, off_A {} < undrl {}); CHECK_VALID (false, void, off_A {} > undrl {}); CHECK_VALID (false, void, off_A {} <= undrl {}); CHECK_VALID (false, void, off_A {} >= undrl {}); static void run_tests () { /* Test op+ and op-. */ { constexpr off_A a {}; static_assert (to_underlying (a) == 0, ""); { constexpr off_A res1 = a + 2; static_assert (to_underlying (res1) == 2, ""); constexpr off_A res2 = res1 - 1; static_assert (to_underlying (res2) == 1, ""); } { constexpr off_A res1 = 2 + a; static_assert (to_underlying (res1) == 2, ""); constexpr off_A res2 = 3 - res1; static_assert (to_underlying (res2) == 1, ""); } } /* Test op+= and op-=. */ { off_A o {}; o += 10; SELF_CHECK (to_underlying (o) == 10); o -= 5; SELF_CHECK (to_underlying (o) == 5); } /* Test op-. */ { constexpr off_A o1 = (off_A) 10; constexpr off_A o2 = (off_A) 20; constexpr unsigned int delta = o2 - o1; static_assert (delta == 10, ""); } /* Test <, <=, >, >=. */ { constexpr off_A o1 = (off_A) 10; constexpr off_A o2 = (off_A) 20; static_assert (o1 < o2, ""); static_assert (!(o2 < o1), ""); static_assert (o2 > o1, ""); static_assert (!(o1 > o2), ""); static_assert (o1 <= o2, ""); static_assert (!(o2 <= o1), ""); static_assert (o2 >= o1, ""); static_assert (!(o1 >= o2), ""); static_assert (o1 <= o1, ""); static_assert (o1 >= o1, ""); } } } /* namespace offset_type */ } /* namespace selftests */ void _initialize_offset_type_selftests () { selftests::register_test ("offset_type", selftests::offset_type::run_tests); }