Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Has GCC13 changed handling of noexcept function pointers?

I have a trait to determine the class of a member function pointer.

In GCC12, it works for both const and const noexcept function pointers.

In GCC13, it no longer works. Clang 16 and MSVC agree with GCC12. If I add a noexcept specialisation, it fixes GCC12, and breaks GCC12/Clang/MSVC.

Is this behaviour specified in the C++ Standard, or is this a GCC bug?

If this is expected behaviour, how can I support both GCC12 and GCC13?

#include <type_traits>

template <auto>
struct get_class;

template <typename Ret, typename Klass, typename... Args, Ret (Klass::*FN)(Args...) const>
struct get_class<FN> : public std::type_identity<Klass>
{};

// Uncomment this to fix GCC13, and break everyone else...
//template <typename Ret, typename Klass, typename... Args, Ret (Klass::*FN)(Args...) const noexcept>
//struct get_class<FN> : public std::type_identity<Klass>
//{};

class MyClass {
public:
    int func1() const noexcept {return 0;}
    int func2() const {return 0;}
};

int main(){
    [[maybe_unused]]get_class<&MyClass::func1>::type x = MyClass{};
    [[maybe_unused]]get_class<&MyClass::func2>::type y = MyClass{};
}

Live example: https://godbolt.org/z/YGv8hxPWd

like image 787
endorph Avatar asked Oct 29 '25 23:10

endorph


1 Answers

Based on this:

noexcept specifier (since C++11) - cppreference.com

The noexcept-specification is not a part of the function type (just like dynamic exception specification) and can only appear as a part of a lambda declarator or a top-level function declarator when declaring functions, variables, non-static data members of type function, pointer to function, reference to function, or pointer to member function, and also when declaring a parameter or a return type in one of those declarations that in turn happens to be a pointer or reference to function. It cannot appear in a typedef or type alias declaration.

void f() noexcept; // the function f() does not throw
void (*fp)() noexcept(false); // fp points to a function that may throw
void g(void pfa() noexcept);  // g takes a pointer to function that doesn't throw
// typedef int (*pf)() noexcept; // error

(until C++17)


The noexcept-specification is a part of the function type and may appear as part of any function declarator. (since C++17)

So in C++17 when noexcept is part of function type, then template specialization should take it into account. So looks like gcc 13 is right and other compilers are wrong.

I've also found something like this: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4533.html

On other hand there is code compatibility issues, so I would not be surprised this could be controlled by some compilation flag (and different default behavior was selected). I would recommend review compiler documentation about this.

Disclaimer I'm not language lawyer so maybe someone can provide better information.

like image 143
Marek R Avatar answered Nov 01 '25 13:11

Marek R