Skip to content

Commit 3d7aa24

Browse files
committed
wildcard matches objects constructible from anything
Unfortunately have to silence warnings when matching creating expectations.
1 parent 9565937 commit 3d7aa24

File tree

4 files changed

+82
-38
lines changed

4 files changed

+82
-38
lines changed

ChangeLog

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
* Fixed issue 293: Wildcard _ could not match types that can be
2+
constructed from any type. This fix unfortunately turns off conversion
3+
warnings for REQUIRE_CALL and friends when building with gcc. Thank
4+
you @TimonNoethlichs for reporting.
5+
16
* Fixed issue 296: Improved sequence violation message when ALLOW_CALL
27
is involved. Thank you Sigurður Sveinn Halldórsson for reporting.
38

compilation_errors/value_from_wildcard.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Project home: https://github.com/rollbear/trompeloeil
1212
*/
1313

14-
// exception: clang++-3
14+
// exception: g++-[678]
1515
// pass: value from wildcard
1616

1717
#include <trompeloeil.hpp>

include/trompeloeil.hpp

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,38 +1091,39 @@ namespace trompeloeil
10911091

10921092
struct wildcard : public matcher
10931093
{
1094-
template <typename T
1095-
#if TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 50000
1096-
,detail::enable_if_t<!std::is_convertible<wildcard&, T>{}>* = nullptr
1097-
#endif
1098-
>
1099-
operator T&&()
1100-
const
1094+
template <typename T>
1095+
struct wrapper {
1096+
operator T() {
1097+
static_assert(std::is_same<T, void>{},
1098+
"Getting a value from wildcard is not allowed.\n"
1099+
"See https://github.com/rollbear/trompeloeil/issues/270\n"
1100+
"and https://github.com/rollbear/trompeloeil/issues/290");
1101+
return *this;
1102+
}
1103+
};
1104+
template <typename T, typename std::enable_if<!std::is_convertible<wildcard&, T>{}>::type* = nullptr>
1105+
operator T()
11011106
{
1102-
#if !TROMPELOEIL_CLANG || TROMPELOEIL_CLANG_VERSION >= 40000
1107+
return wrapper<T>{};
1108+
}
11031109

1104-
static_assert(std::is_same<T, void>{},
1105-
"Getting a value from wildcard is not allowed.\n"
1106-
"See https://github.com/rollbear/trompeloeil/issues/270\n"
1107-
"and https://github.com/rollbear/trompeloeil/issues/290");
1108-
#endif
1110+
template <typename T>
1111+
operator T&&() const
1112+
{
1113+
#if (!TROMPELOEIL_GCC || TROMPELOEIL_GCC_VERSION < 60000 || TROMPELOEIL_GCC_VERSION >= 90000) \
1114+
&& (!TROMPELOEIL_CLANG || TROMPELOEIL_CLANG_VERSION >= 40000 || !defined(_LIBCPP_STD_VER) || _LIBCPP_STD_VER != 14)
1115+
return wrapper<T &&>{};
1116+
#else
11091117
return *this;
1118+
#endif
11101119
}
11111120

1112-
template <typename T
1113-
#if TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 50000
1114-
,detail::enable_if_t<!std::is_convertible<wildcard&, T>{}>* = nullptr
1115-
#endif
1116-
>
1117-
operator T&()
1118-
volatile const // less preferred than T&& above
1121+
template <typename T>
1122+
operator T&() const volatile
11191123
{
1120-
static_assert(std::is_same<T, void>{},
1121-
"Getting a value from wildcard is not allowed.\n"
1122-
"See https://github.com/rollbear/trompeloeil/issues/270\n"
1123-
"and https://github.com/rollbear/trompeloeil/issues/290");
1124-
return *this;
1124+
return wrapper<T&>{};
11251125
}
1126+
11261127
template <typename T>
11271128
constexpr
11281129
bool
@@ -1511,8 +1512,8 @@ template <typename T>
15111512
static
15121513
void
15131514
print(
1514-
std::ostream& os,
1515-
wildcard const&)
1515+
std::ostream& os,
1516+
wildcard const&)
15161517
{
15171518
os << " matching _";
15181519
}
@@ -2354,7 +2355,7 @@ template <typename T>
23542355
// since it doesn't respect the trailing return type declaration on
23552356
// the lambdas of template deduction context
23562357

2357-
#define TROMPELOEIL_MK_PRED_BINOP(name, op) \
2358+
#define TROMPELOEIL_MK_PRED_BINOP(name, op) \
23582359
struct name { \
23592360
template <typename X, typename Y> \
23602361
auto operator()(X const& x, Y const& y) const -> decltype(x op y) \
@@ -2369,7 +2370,7 @@ template <typename T>
23692370
TROMPELOEIL_MK_PRED_BINOP(less_equal, <=);
23702371
TROMPELOEIL_MK_PRED_BINOP(greater, >);
23712372
TROMPELOEIL_MK_PRED_BINOP(greater_equal, >=);
2372-
#undef TROMPELOEIL_MK_PRED_BINOP
2373+
#undef TROMPELOEIL_MK_PRED_BINOP
23732374

23742375
// Define `struct` with `operator()` to replace generic lambdas.
23752376

@@ -2395,7 +2396,7 @@ template <typename T>
23952396

23962397
// These structures replace the `op` printer lambdas.
23972398

2398-
#define TROMPELOEIL_MK_OP_PRINTER(name, op_string) \
2399+
#define TROMPELOEIL_MK_OP_PRINTER(name, op_string) \
23992400
struct name ## _printer \
24002401
{ \
24012402
template <typename T> \
@@ -2415,7 +2416,7 @@ template <typename T>
24152416
TROMPELOEIL_MK_OP_PRINTER(less_equal, " <= ");
24162417
TROMPELOEIL_MK_OP_PRINTER(greater, " > ");
24172418
TROMPELOEIL_MK_OP_PRINTER(greater_equal, " >= ");
2418-
#undef TROMPELOEIL_MK_OP_PRINTER
2419+
#undef TROMPELOEIL_MK_OP_PRINTER
24192420

24202421
}
24212422

@@ -4019,6 +4020,10 @@ template <typename T>
40194020
using call_matcher_base<Sig>::name;
40204021
using call_matcher_base<Sig>::loc;
40214022

4023+
#if TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 70000 && TROMPEOLEIL_GCC_VERSION < 80000
4024+
#pragma GCC diagnostic ignored "-Wconversion"
4025+
#pragma GCC diagnostic push
4026+
#endif
40224027
template <typename ... U>
40234028
call_matcher(
40244029
char const *file,
@@ -4028,6 +4033,9 @@ template <typename T>
40284033
: call_matcher_base<Sig>(location{file, line}, call_string)
40294034
, val(std::forward<U>(u)...)
40304035
{}
4036+
#if TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 70000 && TROMPEOLEIL_GCC_VERSION < 80000
4037+
#pragma GCC diagnostic pop
4038+
#endif
40314039

40324040
call_matcher(call_matcher &&r) = delete;
40334041

@@ -4857,8 +4865,8 @@ template <typename T>
48574865
return ::trompeloeil::mock_func<trompeloeil_movable_mock, TROMPELOEIL_REMOVE_PAREN(sig)>( \
48584866
TROMPELOEIL_LINE_ID(cardinality_match){}, \
48594867
TROMPELOEIL_LINE_ID(expectations), \
4860-
#name, \
4861-
#sig \
4868+
#name, \
4869+
#sig \
48624870
TROMPELOEIL_PARAMS(num)); \
48634871
} \
48644872
\
@@ -4906,7 +4914,14 @@ template <typename T>
49064914
auto TROMPELOEIL_COUNT_ID(call_obj) = \
49074915
TROMPELOEIL_REQUIRE_CALL_V_LAMBDA(obj, func, #obj, #func, __VA_ARGS__)
49084916

4909-
4917+
#if TROMPELOEIL_GCC
4918+
// This is highly unfortunate. Conversion warnings are desired here, but there
4919+
// are situations when the wildcard _ uses conversion when creating an
4920+
// expectation. It would be much better if the warning could be suppressed only
4921+
// for that type. See https://github.com/rollbear/trompeloeil/issues/293
4922+
#pragma GCC diagnostic ignored "-Wconversion"
4923+
#pragma GCC diagnostic push
4924+
#endif
49104925
#define TROMPELOEIL_REQUIRE_CALL_V_LAMBDA(obj, func, obj_s, func_s, ...) \
49114926
[&] \
49124927
{ \
@@ -4919,16 +4934,16 @@ template <typename T>
49194934
__VA_ARGS__ \
49204935
; \
49214936
}()
4922-
4923-
4937+
#if TROMPELOEIL_GCC
4938+
#pragma GCC diagnostic pop
4939+
#endif
49244940
#define TROMPELOEIL_REQUIRE_CALL_LAMBDA_OBJ(obj, func, obj_s, func_s) \
49254941
::trompeloeil::call_validator_t<trompeloeil_s_t>{(obj)} + \
49264942
::trompeloeil::detail::conditional_t<false, \
49274943
decltype((obj).func), \
49284944
trompeloeil_e_t> \
49294945
{__FILE__, static_cast<unsigned long>(__LINE__), obj_s "." func_s}.func
49304946

4931-
49324947
#define TROMPELOEIL_NAMED_REQUIRE_CALL_V(...) \
49334948
TROMPELOEIL_IDENTITY(TROMPELOEIL_NAMED_REQUIRE_CALL_IMPL TROMPELOEIL_LPAREN \
49344949
TROMPELOEIL_MORE_THAN_TWO_ARGS(__VA_ARGS__), __VA_ARGS__))

test/compiling_tests_14.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,30 @@ TEST_CASE_METHOD(
12421242
REQUIRE(reports.empty());
12431243
}
12441244

1245+
struct promiscuous
1246+
{
1247+
template <typename T>
1248+
promiscuous(T&&) {}
1249+
};
1250+
1251+
struct with_promiscuous
1252+
{
1253+
MAKE_MOCK1(func, void(promiscuous));
1254+
};
1255+
1256+
TEST_CASE_METHOD(
1257+
Fixture,
1258+
"C++14: wildcard matches parameter constructible from any type",
1259+
"[C++14][matching]")
1260+
{
1261+
{
1262+
with_promiscuous obj;
1263+
REQUIRE_CALL(obj, func(_));
1264+
obj.func(1);
1265+
}
1266+
REQUIRE(reports.empty());
1267+
}
1268+
12451269
TEST_CASE_METHOD(
12461270
Fixture,
12471271
"C++14: ANY can match unique_ptr<> by value",

0 commit comments

Comments
 (0)