5 ms·
Shouldn't the compiler deduce noexcept for you?
by rwmj 2y ago
Shouldn't the compiler deduce noexcept for you?
- Eyas 2y agoIt probably can in a .cc file but if you're importing another library and just have access to the header, it wouldn't know how to.
- compiler-guy 2y agoThe compiler can tell about the immediate function, but not any functions it calls. If a function marked noexcept calls a function that throws an exception, then the program is terminated with an uncaught exception. A called function can throw through a non-noexcept function to a higher-level exception handler no problem. So in order to avoid changing the semantics of the function, the compiler would have to be able to determine that that transitive closure of called functions dynamically don't throw, and that problem is undecidable, even assuming the requirement that "the compiler can see the source of all those functions" is somehow met, which it won't be.
- terrymah 2y agoNo, we compile in bottom up order, starting with leaf functions, and collecting information about functions as we go. So "not throwing" sort of trickles up when possible to a certain degree. In LTCG (MSVC)/O3 (GCC/Clang) there are prepasses over the entire callgraph to collect this order
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- deleted 2y ago[deleted]
- compiler-guy 2y agoYes of course. Sometimes the compiler can tell. But the original question feels to me more like “Shouldn't the compiler deduce restrict for you?”
- tsimionescu 2y ago> A called function can throw through a non-noexcept function to a higher-level exception handler no problem. This is exactly the problem. To have made this a useful feature, it should have been more restrictive: a noexcept function should not have been allowed to call any function or operator or lambda that is not marked noexcept. Some extra syntax to allow function templates to be made "conditionally noexcept" would have been necessary, but overall the feature would have had a real use and real power to help make code safer, and more performant. Java has the first part down, for the class of checked exceptions: a function that doesn't throw can't call functions that do (except in try/catch blocks, but that's largely irrelevant). The annoyances come because of the missing second part - the ability to make a generic function that throws for some type parameters, but doesn't for others.
- cesarb 2y ago> Java has the first part down, for the class of checked exceptions: a function that doesn't throw can't call functions that do (except in try/catch blocks, but that's largely irrelevant). That's not actually true, it's possible to do "sneaky throws" (https://www.baeldung.com/java-sneaky-throws https://www.baeldung.com/java-sneaky-throws) of a checked exception from a method which isn't declared to throw that checked exception. The classic example is Class.newInstance(), which propagates any exception from the called constructor. Other ways are calling code from JVM languages other than Java, which do not have the same "checked exception" concept (like Kotlin: see https://kotlinlang.org/docs/exceptions.html https://kotlinlang.org/docs/exceptions.html and https://kotlinlang.org/docs/java-to-kotlin-interop.html#checked-exceptions https://kotlinlang.org/docs/java-to-kotlin-interop.html#chec...), generics trickery to confuse the compiler, and manually creating JVM bytecode.
- tsimionescu 2y agoSure, but that's essentially the same as using explicit jumps through raw assembly instructions to go around C++'s destructor guarantees. That is, when your Java process runs non-Java code, of course this can defeat certain Java guarantees. No programming language can make promises for semantics of external code like this.
- lionkor 2y agoNo, noexcept confusingly doesn't mean "does not throw exceptions" in that sense. There is no constraint that says you can only call noexcept code from noexcept code - quite the opposite. Noexcept puts NO constraints on the code. All noexcept does is catch any exception and immediately std::terminate. Confusingly this means that noexcept should really be called deathexcept, since any exception thrown within kills the program.
- nextaccountic 2y agoOh, so it's like Rust's panic=abort
- singron 2y agoPanic=abort is more like -fno-exceptions since it applies to all the code being compiled and not just function. Codegen can also take advantage of the fact that it won't have to unwind. I don't think there is a rust equivalent of noexcept.
- weinzierl 2y agoDoes C++ std::terminate unwind the stack and call destructors? Then noexcept would be pretty close to regular Rust panics, wouldn't it? Basically an unrecoverable exception?
- favorited 2y agoThe behavior of `-fno-exceptions` isn't standardized, because it's a compiler feature, not a part of the C++ standard. The standard says: > In the situation where no matching [exception] handler is found, it is implementation-defined whether or not the stack is unwound before std::terminate is invoked. In the situation where the search for a handler encounters the outermost block of a function with a non-throwing exception specification, it is implementation-defined whether the stack is unwound, unwound partially, or not unwound at all before the function std::terminate is invoked. So, the whole thing is basically implementation-defined (including `-fno-exceptions`, since that is something that implementing compilers provide).
- Arech 2y agoNo, it can't do that. My speculation is that likely it is so because in general case this might be a NP hard problem similar to the halting problem https://en.wikipedia.org/wiki/Halting_problem https://en.wikipedia.org/wiki/Halting_problem. The best it can do is to say whether a given function is qualified with `noexcept` (see noexcept() operator https://en.cppreference.com/w/cpp/language/noexcept https://en.cppreference.com/w/cpp/language/noexcept)
- terrymah 2y agoDude I am going to blow your mind
- Arech 2y agoEeeermm... I haven't heard an explosion, but 4+ hours has passed. Are you alive there, dude? Jokes aside - I'm always happy to be corrected, so please go on if I made a mistake somewhere.
- gpderetta 2y agoYou very likely can't always answer the question "will this function throw?", but it should be relatively easy to identify the subset of function that recursively call functions that are guaranteed not to throw. That's only a subset of all non-throwing functions of course.
- Arech 2y agoYes, my mistake was in confusion a run-time question "will it throw?" with "can it throw in theory?". The latter if I'm not mistaken again only requires a throw statement somewhere in a non-dead code, which is totally possible to find out for a code compiler could see.
- tsimionescu 2y agoI think their point was that the halting problem is NP hard, it is in fact undecidable. Since there is no algorithm that can solve it, there is no point in talking about complexity of that algorithm. Alternatively, Java shows that it is very much possible to do this - the compiler can enforce that a function can't throw exceptions (limited to checked exceptions in Java, but that is besides the point). The way to do it is easy: just check that it doesn't call throw directly, and that all of the functions it calls are also marked noexcept. No need to explore things any deeper than that. Of course, the designers of C++ didn't want to impose this restriction for various reasons.
- olliej 2y agoA lot of people have answered no, which is likely the correct answer to what you're asking, but I wanted to be clear about exactly what that is? Take a hypothetical piece of code some_library_header.h: void library_function(); some_project_header_1.h: void project_function1(); some_project_header_2.h: void project_function2(); some_project_file.cpp: void project_function2() { /* definition */ // no exception } void test_function1() { library_function(); } void test_function2() { project_function1(); } void test_function3() { project_function2(); } For your question, where are you wanting to know if the compiler can deduce noexcept?
- terrymah 2y agoIt absolutely does, and even better, the compiler deduced "this function doesn't throw" doesn't come with the overhead of implementing noexcept proper