digitalmars.D.learn - scope(success) lowered to try-catch ?
- Cauterite (21/22) Jun 17 2018 Hello,
- Nicholas Wilson (10/32) Jun 17 2018 I suspect scope(success) is lowered because scope(exit) and
- Cauterite (3/12) Jun 17 2018 nothrow unfortunately doesn't help; i guess I'll file an issue.
- Steven Schveighoffer (19/46) Jun 17 2018 I think you are right, adding scope(success) should just add the
- Timoses (28/50) Jun 17 2018 In Andrei's book 'The D Programming Language' the following is
- Steven Schveighoffer (11/69) Jun 17 2018 I think the request isn't to integrate the code immediately, but to do:
- Mike Franklin (24/32) Jun 17 2018 You can see what the compiler is doing at
- Neia Neutuladh (28/31) Jun 17 2018 If you had no exception handling in place, you'd need to
- Cauterite (5/6) Jun 18 2018 yeah, at an AST level it makes sense why it was implemented like
- Steven Schveighoffer (24/58) Jun 18 2018 Yep, it's a good point. But also not the only way to do this. If you are...
- aliak (8/13) Jun 18 2018 I'm quite a noob when it comes to compiler stuff, and I see how
Hello, I'm not sure whether I'm missing something obvious here, but is there a reason for scope(success) being lowered to a try-catch statement? I would have expected only scope(exit) and scope(failure) to actually interact with exception handling, while scope(success) simply places code on the path of normal control flow. Example (windows x32): --- // main.d void main() { scope(success) {} }dmd -betterC main.dError: Cannot use try-catch statements with -betterC --- Regardless of whether -betterC is used, you can see in the disassembly that having a scope(success) anywhere in the function causes the SEH prologue to be emitted in the code. Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?
Jun 17 2018
On Sunday, 17 June 2018 at 10:58:29 UTC, Cauterite wrote:Hello, I'm not sure whether I'm missing something obvious here, but is there a reason for scope(success) being lowered to a try-catch statement? I would have expected only scope(exit) and scope(failure) to actually interact with exception handling, while scope(success) simply places code on the path of normal control flow. Example (windows x32): --- // main.d void main() { scope(success) {} }I suspect scope(success) is lowered because scope(exit) and scope(failure) are, and that would result in a simpler (compiler) implementation of it. does adding nothrow to main fix it? For dcompute I specifically allow scope(exit|success) because there will never be any exceptions _at all_. If not, please do submit an issue. Also a better error message should be given.dmd -betterC main.dError: Cannot use try-catch statements with -betterC --- Regardless of whether -betterC is used, you can see in the disassembly that having a scope(success) anywhere in the function causes the SEH prologue to be emitted in the code. Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?
Jun 17 2018
On Sunday, 17 June 2018 at 12:10:33 UTC, Nicholas Wilson wrote:I suspect scope(success) is lowered because scope(exit) and scope(failure) are, and that would result in a simpler (compiler) implementation of it. does adding nothrow to main fix it? For dcompute I specifically allow scope(exit|success) because there will never be any exceptions _at all_. If not, please do submit an issue. Also a better error message should be given.nothrow unfortunately doesn't help; i guess I'll file an issue. thanks for your input
Jun 17 2018
On 6/17/18 6:58 AM, Cauterite wrote:Hello, I'm not sure whether I'm missing something obvious here, but is there a reason for scope(success) being lowered to a try-catch statement? I would have expected only scope(exit) and scope(failure) to actually interact with exception handling, while scope(success) simply places code on the path of normal control flow. Example (windows x32): --- // main.d void main() { scope(success) {} }I think you are right, adding scope(success) should just add the statements to the end of the scope. Here's what I think happens: Because scope(anything) needs to put things like this: try { normal code scope(success) code } catch(Exception e) { scope(failure) code throw e; } finally { scope(exit) code } so any time you use a scope statement, it has to set up this framework so it can have the correct place to put things (there may be scope(failure) or scope(exit) code later). But I think we can fix this. -Stevedmd -betterC main.dError: Cannot use try-catch statements with -betterC --- Regardless of whether -betterC is used, you can see in the disassembly that having a scope(success) anywhere in the function causes the SEH prologue to be emitted in the code. Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?
Jun 17 2018
On Sunday, 17 June 2018 at 10:58:29 UTC, Cauterite wrote:Hello, I'm not sure whether I'm missing something obvious here, but is there a reason for scope(success) being lowered to a try-catch statement? I would have expected only scope(exit) and scope(failure) to actually interact with exception handling, while scope(success) simply places code on the path of normal control flow. Example (windows x32): --- // main.d void main() { scope(success) {} }In Andrei's book 'The D Programming Language' the following is written: { <statement1> scope(success) <statement2> <statement3> } is lowered to { <statement1> bool __succeeded = true; try { <statement3> } catch(Exception e) { __succeeded = false; throw e; } finally { if (__succeeded) <statement2> // vice-versa for scope(failure): `if (!__succeeded) ...` } } If it weren't and it would simply be integrated one would have to write potentiallyThrowingFunc(); scope(success) {...}; I suppose? And this seems like breaking how scope works with failure and exit?!dmd -betterC main.dError: Cannot use try-catch statements with -betterC --- Regardless of whether -betterC is used, you can see in the disassembly that having a scope(success) anywhere in the function causes the SEH prologue to be emitted in the code. Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?
Jun 17 2018
On 6/17/18 8:24 AM, Timoses wrote:On Sunday, 17 June 2018 at 10:58:29 UTC, Cauterite wrote:I think the request isn't to integrate the code immediately, but to do: { <statement 1> <statement 3> <statement 2> } and be just fine. I think the reason the scope(failure) is done that way is likely for proper exception chaining in case one of the scope statements throws. -SteveHello, I'm not sure whether I'm missing something obvious here, but is there a reason for scope(success) being lowered to a try-catch statement? I would have expected only scope(exit) and scope(failure) to actually interact with exception handling, while scope(success) simply places code on the path of normal control flow. Example (windows x32): --- // main.d void main() { scope(success) {} }In Andrei's book 'The D Programming Language' the following is written: { <statement1> scope(success) <statement2> <statement3> } is lowered to { <statement1> bool __succeeded = true; try { <statement3> } catch(Exception e) { __succeeded = false; throw e; } finally { if (__succeeded) <statement2> // vice-versa for scope(failure): `if (!__succeeded) ...` } } If it weren't and it would simply be integrated one would have to write potentiallyThrowingFunc(); scope(success) {...}; I suppose? And this seems like breaking how scope works with failure and exit?dmd -betterC main.dError: Cannot use try-catch statements with -betterC --- Regardless of whether -betterC is used, you can see in the disassembly that having a scope(success) anywhere in the function causes the SEH prologue to be emitted in the code. Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?
Jun 17 2018
On Sunday, 17 June 2018 at 10:58:29 UTC, Cauterite wrote:--- // main.d void main() { scope(success) {} }You can see what the compiler is doing at https://run.dlang.io/is/5BZOQV and clicking on the "AST" button. It produces the following: import object; void main() { bool __os2 = false; try { } catch(Throwable __o3) { __os2 = true; throw __o3; } if (!__os2) { } return 0; } The compiler could probably lower that to something more intelligent so it could be used in -betterC. I rule it a bug. Mikedmd -betterC main.dError: Cannot use try-catch statements with -betterC ---
Jun 17 2018
On Sunday, 17 June 2018 at 10:58:29 UTC, Cauterite wrote:Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?If you had no exception handling in place, you'd need to duplicate code in the output. For instance: void foo() { scope(success) writeln("success!"); if (a) return; if (b) return; throw new Exception; } This would have to be lowered to: void foo() { if (a) { writeln("success!"); return; } if (b) { writeln("success!"); return; } throw new Exception; writeln("success!"); // maybe omitted with flow analysis } Now imagine there were 20 places you return from the function early. Now imagine this is in a loop body, where you can leave it via goto, break, continue, return, or end-of-block. And wrapped in several if statements. You generate smaller code with the exception handling system. The compiler only has to pay attention to scope guards in the code that handles it directly, instead of at every flow control statement. Add to that the fact that -betterC is pretty recent and scope guards are more than ten years old, and you get this hole in the compiler.
Jun 17 2018
On Monday, 18 June 2018 at 03:58:47 UTC, Neia Neutuladh wrote:...yeah, at an AST level it makes sense why it was implemented like this. it's unfortunate that there's no straightforward way to express 'finally(success) {'.
Jun 18 2018
On 6/17/18 11:58 PM, Neia Neutuladh wrote:On Sunday, 17 June 2018 at 10:58:29 UTC, Cauterite wrote:Yep, it's a good point. But also not the only way to do this. If you are returning void, just a goto would work: void foo() { if(a) { goto L1; } if(b) { goto L1; } throw new Exception; L1: writeln("success1"); } If you are returning a value, then you can establish a local variable with the return value, and use a goto that way. It's already doing this with "did it succeed", so adding another local variable is pretty trivial. Bottom line is, the compiler understands flow control and can insert structures like this without a huge impact. I also think it's possible for the compiler to detect that a try/catch clause is trivially omitted if we do it in the right way.Is there a reason scope(success) needs to set up for exception handling? Or is this a bug / potential enhancement ?If you had no exception handling in place, you'd need to duplicate code in the output. For instance: void foo() { scope(success) writeln("success!"); if (a) return; if (b) return; throw new Exception; } This would have to be lowered to: void foo() { if (a) { writeln("success!"); return; } if (b) { writeln("success!"); return; } throw new Exception; writeln("success!"); // maybe omitted with flow analysis }Now imagine there were 20 places you return from the function early. Now imagine this is in a loop body, where you can leave it via goto, break, continue, return, or end-of-block. And wrapped in several if statements.These are all pretty easy to deal with. After all, they are essentially glorified gotos.You generate smaller code with the exception handling system. The compiler only has to pay attention to scope guards in the code that handles it directly, instead of at every flow control statement. Add to that the fact that -betterC is pretty recent and scope guards are more than ten years old, and you get this hole in the compiler.I think the last point here is exactly why it was done this way -- the original design of the compiler was to expect there were always exception handling, so why not use it? -Steve
Jun 18 2018
On Monday, 18 June 2018 at 12:48:46 UTC, Steven Schveighoffer wrote:On 6/17/18 11:58 PM, Neia Neutuladh wrote:I'm quite a noob when it comes to compiler stuff, and I see how this can be optimized when there're no exceptions, but I wonder what scope(success) actually means though without exceptions in play. It's just scope(exit) then right or? Cheers, - Ali[...]Yep, it's a good point. But also not the only way to do this. If you are returning void, just a goto would work: [...]
Jun 18 2018