Previously, the compiler rejected code that contained multiple declarations of malloc, with different non-throwing exception specification, that had been accepted. The problem occurred when merging the two declarations. The code has been adjusted in such a way that the two declarations are merged properly and the code compiles.
The reason we're seeing an error here is that since C++17 'noexcept' is now part of the type system, which means that e.g.
void call (void (*)() noexcept);
void f ();
void
bar ()
{
call (f);
}
doesn't compile in C++17, but this is only enforced in G++ 7 and newer (starting with https://gcc.gnu.org/r241944). A noexcept function can be converted to non-noexcept, but not the other way around--hence the invalid conversion from 'void* (*)(long unsigned int)' to 'void* (*)(long unsigned int) noexcept'. I think the solution is to add a new noexcept overload, or add the noexcept specifier.
Your testcase will compile with G++ 7 with -fno-builtin-malloc, because then the non-noexcept version of malloc defined in the program will be used.
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.
For information on the advisory, and where to find the updated
files, follow the link below.
If the solution does not work for you, open a new bug report.
https://access.redhat.com/errata/RHBA-2018:3562
Description of problem: GCC 7.2 compilation fails over noexcept Version-Release number of selected component (if applicable): devtoolset-7-gcc-c++-7.2.1-1 How reproducible: Always Steps to Reproduce: 1. // no.C #include <type_traits> #include <iostream> #include <atomic> #include <stdlib.h> #include <dlfcn.h> template <typename Return, typename... Args> static Return (*rtld_next(Return (*f)(Args...), const char* symbolVersion = nullptr))(Args...) { Dl_info info; dladdr(reinterpret_cast<void*>(f), &info); auto symbolName = info.dli_sname; // Clear any existing error dlerror(); auto realFunction = reinterpret_cast<decltype(f)>( symbolVersion ? dlvsym(RTLD_NEXT, symbolName, symbolVersion) : dlsym(RTLD_NEXT, symbolName)); return realFunction; } template <typename F, F* Func, typename... Args> static typename std::result_of<F*(Args...)>::type call_next(Args&&... args) { static std::atomic<F*> real{}; if (!real.load(std::memory_order_relaxed)) real.store(rtld_next(Func)); return real.load(std::memory_order_relaxed)(std::forward<Args>(args)...); } void* malloc(size_t size) { return call_next<decltype(malloc), malloc>(size); } void* operator new(std::size_t size) { return call_next < decltype(malloc), ::operator new>(size); } int main() { } Compile with : g++ -std=c++17 -Werror -Wextra no.C Actual results: no2.C: In function 'void* operator new(std::size_t)': no2.C:43:60: error: no matching function for call to 'call_next<void*(size_t) noexcept, operator new>(std::size_t&)' return call_next < decltype(malloc), ::operator new>(size); ^ no2.C:25:53: note: candidate: template<class F, F* Func, class ... Args> typename std::result_of<F*(Args ...)>::type call_next(Args&& ...) static typename std::result_of<F*(Args...)>::type call_next(Args&&... args) ^~~~~~~~~ no2.C:25:53: note: template argument deduction/substitution failed: no2.C:43:60: error: ignoring attributes on template argument 'void*(size_t) noexcept {aka void*(long unsigned int) noexcept}' [-Werror=ignored-attributes] return call_next < decltype(malloc), ::operator new>(size); ^ no2.C:43:60: error: could not convert template argument 'operator new' from '<unresolved overloaded function type>' to 'void* (*)(long unsigned int) noexcep ' no2.C: In instantiation of 'typename std::result_of<F*(Args ...)>::type call_next(Args&& ...) [with F = void*(long unsigned int) noexcept; F* Func = malloc; Args = {long unsigned int&}; typename std::result_of<F*(Args ...)>::type = void*]': no2.C:38:50: required from here no2.C:30:27: error: invalid conversion from 'void* (*)(long unsigned int)' to 'std::atomic<void* (*)(long unsigned int) noexcept>::__pointer_type {aka void* (*)(long unsigned int) noexcept}' [-fpermissive] real.store(rtld_next(Func)); ~~~~~~~~~^~~~~~ In file included from no2.C:3:0: /ms/dist/mstk/PROJ/rhdevtoolset/7.0-rhel6-0/.exec/@sys/include/c++/7/atomic:441:7: note: initializing argument 1 of 'void std::atomic<_Tp*>::store(std::atomic<_Tp*>::__pointer_type, std::memory_order) [with _Tp = void*(long unsigned int) noexcept; std::atomic<_Tp*>::__pointer_type = void* (*)(long unsigned int) noexcept; std::memory_order = std::memory_order]' store(__pointer_type __p, ^~~~~ cc1plus: all warnings being treated as errors Expected results: No warnings Additional info: - Same code compilation goes fine on devtoolset-6-gcc-c++-6.3.1-3.1 with -std=c++17 - No issue with -std=c++14