https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66639
Bug ID: 66639 Summary: Feature request C++: mark __func__ , __FUNCTION__ & __PRETTY_FUNCTION__ as constexpr Product: gcc Version: 5.1.1 Status: UNCONFIRMED Severity: enhancement Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: simon at gleissner dot de Target Milestone: --- Currently, __func__ , __FUNCTION__ and __PRETTY_FUNCTION__ are internally declared as static constant arrays: static const char __func__[] = "function-name"; If compiled as C++11/14, it might be possible to declare them as 'constexpr', to fully enable them for constexpr functions. I have written an exception wrapper to precompile the error text (as C++14, see below). Basically, the following code concatenate strings during compile time, not at run time. The text is thrown during a std::system_error as the 'what'-argument. The interesting part is in the THROW_SYSTEM_ERROR macro, where i use __PRETTY_FUNCTION__. The code works and the output is (as expected) Exception in 'int main()' by 'testfunc()': Invalid argument (system:22) When we look in the compiled code (-O3 or -Os), a precompiled struct object with the precompiled string "in 'int main()' by 'testfunc()'" is pushed onto the stack byte for byte: call __cxa_allocate_exception movq %rax, %rbx movb $105, (%rsp) movb $110, 1(%rsp) movb $32, 2(%rsp) movb $39, 3(%rsp) movb $105, 4(%rsp) movb $110, 5(%rsp) movb $116, 6(%rsp) movb $32, 7(%rsp) movb $109, 8(%rsp) movb $97, 9(%rsp) movb $105, 10(%rsp) movb $110, 11(%rsp) movb $40, 12(%rsp) movb $41, 13(%rsp) movb $39, 14(%rsp) movb $32, 15(%rsp) movb $98, 16(%rsp) movb $121, 17(%rsp) movb $32, 18(%rsp) movb $39, 19(%rsp) movb $116, 20(%rsp) movb $101, 21(%rsp) movb $115, 22(%rsp) movb $116, 23(%rsp) movb $102, 24(%rsp) movb $117, 25(%rsp) movb $110, 26(%rsp) movb $99, 27(%rsp) movb $40, 28(%rsp) movb $41, 29(%rsp) movb $39, 30(%rsp) movb $0, 31(%rsp) call _ZNSt3_V215system_categoryEv This is not really what i have expected, but because i use a temporary object, it is understandable. However, when i use a static constexpr object for the precompiled text (enable the disabled macro in the source), i get the error messages ../src/Tests.cpp:112:111: error: the value of ‘__PRETTY_FUNCTION__’ is not usable in a constant expression ../src/Tests.cpp:112:65: note: ‘__PRETTY_FUNCTION__’ was not declared ‘constexpr As __PRETTY_FUNCTION__ can already be used in constexpr functions at compile time, i don't think that this change might be very big. //============================================================================ // Name : Tests.cpp // Author : Simon Gleissner //============================================================================ #include <iostream> #include <system_error> #include <cerrno> #include <cstring> namespace MyLib { template<typename... CHARS> struct Message { constexpr Message(CHARS... chars) : str {chars...,'\0'} {} const char str[sizeof...(CHARS)+1]; }; // we can not specialize a function template parially, // therefore we have to wrap it statically inside a class // (which can partially be specialized) template<unsigned COUNTDOWN_A, unsigned COUNTDOWN_B, unsigned COUNTDOWN_C> struct CharIndexer { template<unsigned SIZE_A, unsigned SIZE_B, unsigned SIZE_C, typename... CHARS> static constexpr auto CreateChars( const char (&str_a)[SIZE_A], const char (&str_b)[SIZE_B], const char (&str_c)[SIZE_C], CHARS... chars) { return CharIndexer<COUNTDOWN_A-1, COUNTDOWN_B, COUNTDOWN_C>::CreateChars(str_a, str_b, str_c, chars..., str_a[SIZE_A-COUNTDOWN_A]); } }; template<unsigned COUNTDOWN_B, unsigned COUNTDOWN_C> struct CharIndexer<1, COUNTDOWN_B, COUNTDOWN_C> { template<unsigned SIZE_A, unsigned SIZE_B, unsigned SIZE_C, typename... CHARS> static constexpr auto CreateChars( const char (&str_a)[SIZE_A], const char (&str_b)[SIZE_B], const char (&str_c)[SIZE_C], CHARS... chars) { return CharIndexer<1, COUNTDOWN_B-1, COUNTDOWN_C>::CreateChars(str_a, str_b, str_c, chars..., str_b[SIZE_B-COUNTDOWN_B]); } }; template<unsigned COUNTDOWN_C> struct CharIndexer<1, 1, COUNTDOWN_C> { template<unsigned SIZE_A, unsigned SIZE_B, unsigned SIZE_C, typename... CHARS> static constexpr auto CreateChars( const char (&str_a)[SIZE_A], const char (&str_b)[SIZE_B], const char (&str_c)[SIZE_C], CHARS... chars) { return CharIndexer<1, 1, COUNTDOWN_C-1>::CreateChars(str_a, str_b, str_c, chars..., str_c[SIZE_C-COUNTDOWN_C]); } }; template<> struct CharIndexer<1, 1, 1> { template<unsigned SIZE_A, unsigned SIZE_B, unsigned SIZE_C, typename... CHARS> static constexpr auto CreateChars( const char (&str_a)[SIZE_A], const char (&str_b)[SIZE_B], const char (&str_c)[SIZE_C], CHARS... chars) { return Message<CHARS...>(chars...); } }; template<unsigned A, unsigned B, unsigned C> constexpr auto concatenate(const char (&a)[A], const char (&b)[B], const char (&c)[C]) { return CharIndexer<A,B,C>::CreateChars(a,b,c); } } // namespace MyLib #if 0 #define THROW_SYSTEM_ERROR(ERROR_NO, CAUSE) \ do { \ constexpr static auto what = MyLib::concatenate( \ "in '", __PRETTY_FUNCTION__, "' by '" CAUSE "'"); \ throw std::system_error(ERROR_NO, \ std::system_category(), what.str); \ } while(0) #endif #define THROW_SYSTEM_ERROR(ERROR_NO, CAUSE) \ throw std::system_error(ERROR_NO, std::system_category(), \ MyLib::concatenate("in '", __PRETTY_FUNCTION__, "' by '" CAUSE "'").str) int main() { try { THROW_SYSTEM_ERROR(EINVAL, "testfunc()"); } catch(const std::system_error& exception) { std::cerr << "Exception " << exception.what() << " (" << exception.code() << ")" << std::endl; } return 0; }