ned14 / outcome

Provides very lightweight outcome<T> and result<T> (non-Boost edition)
https://ned14.github.io/outcome
Other
675 stars 62 forks source link

Worked example for experimental features failed to compile on g++-7 #254

Closed lzhangzz closed 2 years ago

lzhangzz commented 2 years ago

I'm going through the example of adding custom code domain, but experimental_status_code.cpp failed to compile on g++-7.5.0 (outcome 2.2.1, -std=c++14/17), with the following message

outcome-experimental.hpp:7027:114: fatal error: template instantiation depth exceeds maximum of 900 (use -ftemplate-depth= to increase the maximum)
   template <class T, class... Args> using get_make_status_code_result = decltype(make_status_code(std::declval<T>(), std::declval<Args>()...));

I also tested on g++8/9 and it seems OK.

lzhangzz commented 2 years ago

After digging around for a while, I can see that just using T = detail::safe_get_make_status_code_result<file_io_error>::type somewhere can reproduce the infinite recursion on gcc-7. It seems the variadic ctor of status_code is somehow involved in safe_get_make_status_code_result, but this doesn't happen on gcc-8+.

I tried to search similar known issues of gcc but couldn't find one. Any comments on possible origin of the problem or possible workaround for gcc-7?

ned14 commented 2 years ago

Sorry for the late reply. I was on vacation.

GCC7 is definitely working with status code. Indeed, LLFIO's status code build is CI-ed using GCC7, and most of my LLFIO dev work is with GCC7. But I wouldn't be surprised if a few metaprogramming corner cases are rough on GCC7 i.e. it'll work 99% of the time.

Have you given https://github.com/ned14/status-code/blob/master/example/quick_status_code_from_enum.cpp a try? For 99% of custom code domains, it'll "just work". It also requires a lot less typing and boilerplate, most people just copy and paste an existing one and give it a new GUID and they're done. As a result, they are quite popular with devs!

lzhangzz commented 2 years ago

Thanks for your reply.

To reproduce the problem: https://godbolt.org/z/azMKPcTbY

It seems a declaration of make_status_code(T), with T being a stats_code<...> (which is not included in test cases) can trigger the problem on GCC7.

ned14 commented 2 years ago

The thing is, it's absolutely valid that you can make a status code whose payload is another status code, and moreover that's quite useful. So the preconditions only filter out making a status code whose payload is the exact same status code.

If you can find a workaround for GCC7 which doesn't break semantics on other compilers, I would consider adopting such a workaround. But, in general, I'm not keen on on going nuts supporting bugs in legacy compilers. It's rare that somebody is actually locked into a specific version of GCC without choice, most also have the option of clang or a different version of GCC, even on embedded toolchains, though it's usually more work and hassle for them to go compile a newer compiler.

BTW did you notice that your bug doesn't appear in GCC 6? There the code works fine. This only affects GCC 7 as far as I can tell.

lzhangzz commented 2 years ago

No, it's not working for GCC 6 either. In the above link, all the codes are commented out by an #if requiring GCC version > 6, since it's directly copied from the example. Same error occurs on GCC6 if the #if is removed.

In my case, GCC 7 is the lowest GCC version to support in my current project, chosen by our organization. Currently status_code is the only dependency that I'm trying bring in with issues with GCC 7. As the feature is indeed quite useful, I will try to find a workaround for GCC 7.

ned14 commented 2 years ago

Oh I'm sorry. I didn't pay attention to it, I just chose GCC6 in godbolt and it seemed to work. If it's any help, this regression on GCC 7 in the worked examples must surely be because of a fix to correctness made to status code since the worked examples were originally written. i.e. a bug got fixed, and it got fixed in a way which broke GCC 7.

I would also remind you that I'm using GCC7 with experimental Outcome in a large production codebase and I can confirm it's working well i.e. just because an individual worked example or two fails doesn't mean it's not usable in production (that said, I agree I'd feel anxiety choosing a library which didn't pass all its tests on the compiler I have to support). Anyway good luck with the workaround hunting!