Project: mesos
Issue MESOS-3141: Compiler warning when mocking function type has an enum return type.
The purpose of this ticket is to document a very cryptic error message (actually a warning that gets propagated by {{-Werror}}) that gets generated by {{clang-3.5}} from {{gmock}} source code when trying to mock a perfectly innocent-looking function. h3. Problem The following code is attempting to mock a {{MesosExecutorDriver}}: {code} class MockMesosExecutorDriver : public MesosExecutorDriver { public: MockMesosExecutorDriver(mesos::Executor* executor) : MesosExecutorDriver(executor) {} MOCK_METHOD1(sendStatusUpdate, Status(const TaskStatus&)); }; {code} The above code generates the following error message: {noformat} In file included from ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock.h:58: In file included from ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-actions.h:46: ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/internal/gmock-internal-utils.h:355:10: error: indirection of non-volatile null pointer will be deleted, not trap [-Werror,-Wnull-dereference] return *static_cast::type*>(__null); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-actions.h:78:22: note: in instantiation of function template specialization 'testing::internal::Invalid' requested here return internal::Invalid(); ^ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-actions.h:190:43: note: in instantiation of member function 'testing::internal::BuiltInDefaultValue::Get' requested here internal::BuiltInDefaultValue::Get() : *value_; ^ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-spec-builders.h:1435:34: note: in instantiation of member function 'testing::DefaultValue::Get' requested here return DefaultValue::Get(); ^ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-spec-builders.h:1334:22: note: in instantiation of member function 'testing::internal::FunctionMockerBase::PerformDefaultAction' requested here func_mocker->PerformDefaultAction(args, call_description)); ^ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-spec-builders.h:1448:26: note: in instantiation of function template specialization 'testing::internal::ActionResultHolder::PerformDefaultAction' requested here return ResultHolder::PerformDefaultAction(this, args, call_description); ^ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/gmock-generated-function-mockers.h:81:7: note: in instantiation of member function 'testing::internal::FunctionMockerBase::UntypedPerformDefaultAction' requested here class FunctionMocker : public ^ ../3rdparty/libprocess/3rdparty/gmock-1.6.0/include/gmock/internal/gmock-internal-utils.h:355:10: note: consider using __builtin_trap() or qualifying pointer with 'volatile' return *static_cast::type*>(__null); ^ {noformat} The source of the issue here is that {{Status}} is an {{enum}}. In {{gmock-1.6.0/include/gmock/internal/gmock-internal-utils.h}} you can find the following function: {code} template T Invalid() { return *static_cast::type*>(NULL); } {code} This function gets called with the return type of a mocked function. In our case, the return type of the mocked function is {{Status}}. Attempting to compile the following minimal example with {{clang-3.5}} reproduces the error message: {code} #include template T invalid() { return *static_cast::type *>(nullptr); } enum E { A, B }; int main() { invalid(); } {code} * See it online on [GCC Explorer|https://goo.gl/t1FepZ] Note that if the type is not an {{enum}}, the warning is not generated. This is why existing mocked functions that return non-{{enum}} types such as {{Future}} does not encounter this issue. h3. Solutions The simplest solution is to add {{-Wno-null-deference}} to {{mesos_tests_CPPFLAGS}} in {{src/Makefile.am}}. {code} mesos_tests_CPPFLAGS = $(MESOS_CPPFLAGS) -Wno-null-dereference {code} Another solution is to upgrade {{gmock}} from *1.6* to *1.7* because this problem is solved in the newer versions. In gmock 1.7 {code} template inline T Invalid() { return const_cast::type&>( *static_cast::type*>(NULL)); } {code} Add volatile could avoid this warning. https://goo.gl/opCiLC
Story points: 3