November 06, 2018
On Tuesday, 6 November 2018 at 01:05:04 UTC, Neia Neutuladh wrote:
> In C++, if you skip over `int i = 10;` it's an error, but not if you skip over `int i;`.

In fact I agree with that rule more than the D one to be honest. Since It isn't initialized and never used, I think a warning should be enough instead of an error.

On the other hand, if there is a possibility that the variable can be accessed, then an error should be throw.

Like:

{
   goto Q:
   int x;
   Q:
   x = 10; // An error is ok.
}

But here:

{
   goto Q:
   int x; // An warning should be enough in my IMHO.
   Q:
   return;
}

MatheusBN.
November 05, 2018
On Monday, November 5, 2018 7:55:46 PM MST MatheusBN via Digitalmars-d-learn wrote:
> On Tuesday, 6 November 2018 at 01:55:04 UTC, Jonathan M Davis
>
> wrote:
> >> And I found a bit strange that in such code, since "x" is never used, why it isn't skipped.
> >
> > It's skipped right over. The goto jumps out of the scope, and the line with
> >
> > int x;
> >
> > is never run. In fact, if you compile with -w or -wi, the compiler will give you a warning about unreachable code.
>
> That is exactly my point.
>
> Since "x" it's skipped and never used, it shouldn't just be a warning (unreachable code) instead of an error?
>
> I'm trying to understand why/when such code could give any problem.
>
> On the other hand if the code were:
>
> {
>     goto Q:
>     int x;
>
>     Q:
>     x = 10; // <- Now you are accessing an uninitialized variable.
> }
>
> Then I think an error would be ok.

D tries to _very_ little with code flow analysis, because once you start having to do much with it, odds are that the compiler implementation is going to get it wrong. As such, any feature that involves code flow analysis in D tends to be _very_ simple. So, D avoids the issue here by saying that you cannot skip the initialization of a variable with goto. The compiler is not going to do the complicated logic of keeping track of where you access the variable in relation to the goto. That's exactly the sort of thing that might be obvious in the simple case but is highly likely to be buggy in more complex code. Code such as

{
    goto Q;
    int x;
}
Q:

or

{
    if(foo)
        goto Q;
    int x;
}
Q:


is fine, because the compiler can trivially see that it is impossible for x to be used after it's been skipped, whereas with something like

goto Q;
int x;
Q:

the compiler has to do much more complicated analysis of what the code is doing in order to determine that, and when the code isn't trivial, that can get _really_ complicated.

You could argue that it would be nicer if the language required that the compiler be smarter about it, but by having the compiler be stupid, it reduces the risk of compiler bugs, and most people would consider code doing much with gotos like this to be poor code anyway. Most of the cases where goto is reasonable tend to be using goto from inside braces already, because it tends to be used as a way to more efficiently exit deeply nested code. And with D's labeled break and continue, the need for using goto outside of switch statements also tends to be lower than it is in C/C++.

- Jonathan M Davis



November 06, 2018
On Tuesday, 6 November 2018 at 05:46:40 UTC, Jonathan M Davis wrote:
> On Monday, November 5, 2018 7:55:46 PM MST MatheusBN via Digitalmars-d-learn wrote:
>> On Tuesday, 6 November 2018 at 01:55:04 UTC, Jonathan M Davis
>>
>> wrote:
>> >> And I found a bit strange that in such code, since "x" is never used, why it isn't skipped.
>> >
>> > It's skipped right over. The goto jumps out of the scope, and the line with
>> >
>> > int x;
>> >
>> > is never run. In fact, if you compile with -w or -wi, the compiler will give you a warning about unreachable code.
>>
>> That is exactly my point.
>>
>> Since "x" it's skipped and never used, it shouldn't just be a warning (unreachable code) instead of an error?
>>
>> I'm trying to understand why/when such code could give any problem.
>>
>> On the other hand if the code were:
>>
>> {
>>     goto Q:
>>     int x;
>>
>>     Q:
>>     x = 10; // <- Now you are accessing an uninitialized variable.
>> }
>>
>> Then I think an error would be ok.
>
> D tries to _very_ little with code flow analysis, because once you start having to do much with it, odds are that the compiler implementation is going to get it wrong. As such, any feature that involves code flow analysis in D tends to be _very_ simple. So, D avoids the issue here by saying that you cannot skip the initialization of a variable with goto. The compiler is not going to do the complicated logic of keeping track of where you access the variable in relation to the goto. That's exactly the sort of thing that might be obvious in the simple case but is highly likely to be buggy in more complex code. Code such as
>
> {
>     goto Q;
>     int x;
> }
> Q:
>
> or
>
> {
>     if(foo)
>         goto Q;
>     int x;
> }
> Q:
>
>
> is fine, because the compiler can trivially see that it is impossible for x to be used after it's been skipped, whereas with something like
>
> goto Q;
> int x;
> Q:
>
> the compiler has to do much more complicated analysis of what the code is doing in order to determine that, and when the code isn't trivial, that can get _really_ complicated.
>
> You could argue that it would be nicer if the language required that the compiler be smarter about it, but by having the compiler be stupid, it reduces the risk of compiler bugs, and most people would consider code doing much with gotos like this to be poor code anyway. Most of the cases where goto is reasonable tend to be using goto from inside braces already, because it tends to be used as a way to more efficiently exit deeply nested code. And with D's labeled break and continue, the need for using goto outside of switch statements also tends to be lower than it is in C/C++.
>
> - Jonathan M Davis

It's clear now about this decision and by the way thanks for replying all my doubts.

MatheusBN.
November 07, 2018
On Tuesday, 6 November 2018 at 13:53:41 UTC, MatheusBN wrote:
> On Tuesday, 6 November 2018 at 05:46:40 UTC, Jonathan M Davis wrote:
>> On Monday, November 5, 2018 7:55:46 PM MST MatheusBN via Digitalmars-d-learn wrote:
>>> On Tuesday, 6 November 2018 at 01:55:04 UTC, Jonathan M Davis
>>>
>>> wrote:
>>> >> And I found a bit strange that in such code, since "x" is never used, why it isn't skipped.
>>> >
>>> > It's skipped right over. The goto jumps out of the scope, and the line with
>>> >
>>> > int x;
>>> >
>>> > is never run. In fact, if you compile with -w or -wi, the compiler will give you a warning about unreachable code.
>>>
>>> That is exactly my point.
>>>
>>> Since "x" it's skipped and never used, it shouldn't just be a warning (unreachable code) instead of an error?
>>>
>>> I'm trying to understand why/when such code could give any problem.
>>>
>>> On the other hand if the code were:
>>>
>>> {
>>>     goto Q:
>>>     int x;
>>>
>>>     Q:
>>>     x = 10; // <- Now you are accessing an uninitialized variable.
>>> }
>>>
>>> Then I think an error would be ok.
>>
>> D tries to _very_ little with code flow analysis, because once you start having to do much with it, odds are that the compiler implementation is going to get it wrong. As such, any feature that involves code flow analysis in D tends to be _very_ simple. So, D avoids the issue here by saying that you cannot skip the initialization of a variable with goto. The compiler is not going to do the complicated logic of keeping track of where you access the variable in relation to the goto. That's exactly the sort of thing that might be obvious in the simple case but is highly likely to be buggy in more complex code. Code such as
>>
>> {
>>     goto Q;
>>     int x;
>> }
>> Q:
>>
>> or
>>
>> {
>>     if(foo)
>>         goto Q;
>>     int x;
>> }
>> Q:
>>
>>
>> is fine, because the compiler can trivially see that it is impossible for x to be used after it's been skipped, whereas with something like
>>
>> goto Q;
>> int x;
>> Q:
>>
>> the compiler has to do much more complicated analysis of what the code is doing in order to determine that, and when the code isn't trivial, that can get _really_ complicated.
>>
>> You could argue that it would be nicer if the language required that the compiler be smarter about it, but by having the compiler be stupid, it reduces the risk of compiler bugs, and most people would consider code doing much with gotos like this to be poor code anyway. Most of the cases where goto is reasonable tend to be using goto from inside braces already, because it tends to be used as a way to more efficiently exit deeply nested code. And with D's labeled break and continue, the need for using goto outside of switch statements also tends to be lower than it is in C/C++.
>>
>> - Jonathan M Davis
>
> It's clear now about this decision and by the way thanks for replying all my doubts.
>
> MatheusBN.

Don't let their psychobabble fool you. They are wrong and you were right from the start.

There is no initialization of the variable, or, if there is(because it's "on the tack, which is "initialized" at the start of the function"), the variable is still never used and that is the whole problem.

What you will find with some of these guys is they start with the assumption that everything D does is correct then they try to disprove anything that goes against it by coming up with reasons that explain why D does it the way it does. It is circular reasoning and invalid. Each step they come up with some new explanation when you pick holes in their previous ones.

Eventually it's either "It's because D is not designed to do that" or "write an enhancement yourself" type of answer.


The fact is simple: Who ever implemented the goto statement did not create code to handle this case and chose the easiest route which is to error out. This was either oversight or "laziness".

It's really simple as that. Not once has anyone proven that the semantics are illogical, which is what it would require for the compiler to be absolutely correct in it's error.


In this case, they are simple wrong because it requires no flow analysis or any complex logic to determine. It's not because C is stupid and is unsafe, it's unreachable, etc...


The compiler simply knows what line and scope a variable is initialized on(since it can determine if a variable is used for initialization, which is a logic error) and it simply has to determine if the goto escapes the scope before using any initialized variable.

It can do this easily but the logic was not added.

Case A:
{
   if (true) goto X;
   int x;
}
X:


Case B:
{
   if (true) goto X;
   {
      int x;
   }
}
X:


These two cases are EXACTLY the same semantically. It's like writing A + B and (A + B).

What the extra scope does though is create a new scope in the compiler AST and this separates the goto logic, which is properly implemented to handle that case.

The fact that one produces one error and the other is valid proves that the compiler is incomplete. Adding scopes does not change semantics no different than adding parenthesis(which is just scope). ((((((3)))))) is the same as 3. (obviously not all scopes can be eliminated in all cases, but this isn't one of those cases)


And, so, the real answer is simply the compiler does not test this case. My point with the previous post was to point it out... but as you see, a lot of the fanboys come in and simply defend what D does as if it is the most valid way from the get go. This is their mind set. They reason from their conclusions. I've seen them do it quite often. I'm not sure what the motivations are. If they don't understand the problem(Sometimes simple is very confusing for some) or if they want to obfuscate or what.


The idea for any sane person would be to check and see if the code has a semantically logical meaning first. In this case it does. Goto is a common control flow feature and sometimes necessary to greatly simplify certain problems(since D does not have the ability to escape nested scopes such as return3, which returns from 3 nested scopes in).

If one can transform logically the "offending" code in to a semantically equivalent piece of code(this is known as mathematical transformation, such as rewriting a mathematical expression using logically valid rules) that involves no real changes(such as adding scopes), and one fails and the other doesn't, it means the compiler has a bug.

It's like when people drop parenthesis: (3 + 4)*2 =?= 3 + 4*2.

It's illogical. If the compiler did this transformation it would produce invalid results and it would be impossible to reason about code.

If the compiler gives errors for one of two identical mathematical tree's(remember, programs are just mathematical formulas, just really complex, but AST's abstractly the same) then the compiler has a problem.

It's like saying that (3 + 4)*2 is invalid but 3*2 + 4*2 is valid.

It means the compiler did not implement the distributive property.

People that don't know what they are talking about will then try to justify why one works and the other doesn't using some circular or invalid logic rather than actually understanding what is going on. It is damn near impossible to reason with these people because they always start with their conclusion and try to make all the pieces fit that conclusion. Sometimes they eventually come around to a logical conclusion but only they've created a rats nest of reasons and cannot proceed any further but to say, basically, "it is what it is".

The problem is they still never understand what the actual problem is... (because of the rats nest they have just made themselves even more confused)

The problem with the goto is clearly stated and to counter it as being illogical one must simply prove one example where it would result in invalid logic(not crapping out the compiler... the compiler is not perfect and so will have bugs and errors in it. The goal is not to justify those bugs and errors but to fix them so the compiler does a better job and is more logically expressive).



e.g., two cases (the `Case` term is not part of a switch in D, just use to denote the two possible scenarios)


Case A:

{
   if (true) goto X;
   int x;
}
X:


Case B:

{
   if (true) goto X;
   {
      int x;
   }
}
X:

Why is case A any different than case B(in general, the above is an example, the compiler might optimize things, which we don't want to do since optimizations are secondary effects that are not as important as logical consistency)? We are simply talking about the pure semantics of programming. It doesn't really matter what language we use to express it, This is not a problem in D but a problem in programming languages. The question is simply: Are the two case semantically equivalent? (e.g., does (3) = 3? (5) = 5, (x) = x, (((((x+y*3))))) = x+y*3, etc )

Since we are not thinking of any specific compiler(although we have to use the syntax and language grammar of D since ultimately it has to do with D and it has to be expressed in some language, so D is the obvious choice) we can't use circular reasoning(e.g., D does it this way and D is right so...).

Now, the fact is, these are identical statements semantically... trivially so. It really can't get any simpler. Doesn't matter what D does. If D can't see that then D is incomplete.

Now, since we ultimately have to translate in to D and compilers do strange things, it is possible that *in D* they are not identical. E.g., if D inserted initialization of locals at the start of scope and de-initializers at the end of scope, they would not be the same.


which one could express as:

Case A:

int x;
{
   if (true) goto X;
   //int x;
}
~x;
X:


Case B:

{
   if (true) goto X;
   int x;
   {
      //int x;
   }
   ~x;
}
X:

Which, it is clear that x is initialized before the goto in case A and after in case B. This could cause problems(chances are if D did something like this then it would result in invalid programs and compilers bugs at some point).


Sometimes though, because compilers are very complex, it is necessary to prevent certain cases from occurring so certain other semantics can be used. Sometimes compilers simply crap out precisely because that is the easiest thing to do. Of course, if this is done, someone should know about it and be able to explain why the compiler chose to do this rather than the most logical thing.

Don't let people bludgeon you in to submission. Truth and logic is not dictatorial but absolute.





November 07, 2018
On Wednesday, 7 November 2018 at 20:03:47 UTC, Michelle Long wrote:

> Case A:
>
> int x;
> {
>    if (true) goto X;
>    //int x;
> }
> ~x;
> X:

That is not "Case A". This one is:

{
    if (true) goto X;
    T x;

    X:
} // x.__dtor

That should error as an easy cop-out, nothing wrong with that approach. However, this:

{
    if (true) goto X;
    T x;
} // x.__dtor
X:

should not error at all, since goto skips both initialization and use. No one is disputing that. From your posts if I understand correctly it's that second case that errors in your code. If it does, there's a bug, but it's on you to provide a test case. Simple as that. Yet you're all wound up as if the world is out to get you.
November 07, 2018
On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via Digitalmars- d-learn wrote:
> Don't let their psychobabble fool you. They are wrong and you were right from the start.

...

> Case A:
> {
>     if (true) goto X;
>     int x;
> }
> X:
>
>
> Case B:
> {
>     if (true) goto X;
>     {
>        int x;
>     }
> }
> X:
>
>
> These two cases are EXACTLY the same semantically. It's like
> writing A + B and (A + B).

That's not the situation that the OP was describing. If adding braces in a situation where the braces have no semantic effect has any impact on goto, then it's a compiler bug. It's adding a new scope that affects the lifetime of a variable whose declaration is being jumped over by a goto that matters.

I know that you're frustrated, because you've hit a problem with goto in complex code, and you don't have a simple example that shows the compiler bug, but the approach that D takes with goto (and any construct that potentially requires code flow analysis) of avoiding requiring that the compiler be smart is precisely to reduce the risk of there being cases where the compiler is going to screw it up in complex code even though it gets it right in the simple cases. If the language required the compiler to be smart about such things, we'd have a lot more problems with subtle, hard to track down compiler bugs in complex code. So, we'd just have _more_ cases where people would be hitting frustrating bugs like you are.

Regardless, if you want to actually have your problem fixed, you're going to need to provide a reproducible test case in a bugzilla report, even if it's large, otherwise no one is going to be able to track it down for you.

Now, a goto-related regression has recently been reported for joiner:

https://issues.dlang.org/show_bug.cgi?id=19213

where some code worked with joiner in 2.081.2 but does not work with 2.082.0 or later, so you may want to test your code with an older compiler release to see if you've hit a compiler regression. If so, that could be a starting point for tracking down the problem.

- Jonathan M Davis



November 08, 2018
On Thursday, 8 November 2018 at 02:22:42 UTC, Jonathan M Davis wrote:
> On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via Digitalmars- d-learn wrote:
>> Don't let their psychobabble fool you. They are wrong and you were right from the start.
>
> ...
>
>> Case A:
>> {
>>     if (true) goto X;
>>     int x;
>> }
>> X:
>>
>>
>> Case B:
>> {
>>     if (true) goto X;
>>     {
>>        int x;
>>     }
>> }
>> X:
>>
>>
>> These two cases are EXACTLY the same semantically. It's like
>> writing A + B and (A + B).
>
> That's not the situation that the OP was describing. If adding braces in a situation where the braces have no semantic effect has any impact on goto, then it's a compiler bug. It's adding a new scope that affects the lifetime of a variable whose declaration is being jumped over by a goto that matters.
>
> I know that you're frustrated, because you've hit a problem with goto in complex code, and you don't have a simple example that shows the compiler bug, but the approach that D takes with goto (and any construct that potentially requires code flow analysis) of avoiding requiring that the compiler be smart is precisely to reduce the risk of there being cases where the compiler is going to screw it up in complex code even though it gets it right in the simple cases. If the language required the compiler to be smart about such things, we'd have a lot more problems with subtle, hard to track down compiler bugs in complex code. So, we'd just have _more_ cases where people would be hitting frustrating bugs like you are.

That's fine. The D compiler writers can decide to do whatever they want. I can simply take my "business" elsewhere if I don't like it.

What I am talking about is about an obvious error(Ok, I haven't produced a simplified test case but dustmite or visual D is not working for me to do so at this point in time, but it would be nice for sake of argument to assume I'm right...).

> Regardless, if you want to actually have your problem fixed, you're going to need to provide a reproducible test case in a bugzilla report, even if it's large, otherwise no one is going to be able to track it down for you.

That's easier said than done. I wasn't expecting anyone to be able to fix a bug that can't be reproduced.

What I expect is that, given my assumptions that I'm right, that people can agree the compiler does have a bug or flaw that can easily be fixed give then two simplified test cases basic purely what I have done in my own code.

1.

foreach(...)
{
  if (x) goto Y:
  int z;
}
Y:

Fails.

foreach(...)
{
  if (x) goto Y:
  {
     int z;
  }
}
Y:

Passes.

THAT IS FACT! It doesn't matter if the examples work above. I have simplified what I have done and in my code I simply add brackets and it works! That is what people should be thinking about... not test cases, MWE's, compiler versions, etc.

Is it logical that the compiler **should** error out in the first case and no in the second?

That is what the discussion is ALL about. Once that is dealt with then we can move on to finding out more specifics. There is no reason to build the windows of a house before the foundation, it's just far more work without any benefit.


Once people can say: If that is all you are doing is adding brackets around what follows the goto and break out of scope(which is what the code above says) and you can compile, then it is a compiler bug or flaw.

Once people verify that, rather than trying to create rabbit holes, then I can do more work on finding out more specifics. Until then, it is pointless to do anything on my side because if people come back and say "No, it is suppose to work that way" then what the hell am I trying to simplify and fix? It's not a bug then.


But what it seems is that people cannot reason about the purely theoretical underpinnings of the problem and need proof that there is even a problem in the first place, as if I'm making it up and then they create all kinds of obfuscation that doesn't help anyone.

If you can agree that removing the brackets in the two test cases should work in ALL regular cases then I can attempt to provide more information.

Again, until then, it is pointless. I could waste 10 hours trying to track the issue down to provide a test case and you can just come back and say "Oh, no, that is not a bug, it's suppose to be that way. We will not change anything". I know from previous history that is the typical mentality.

Until We can agree that it is a bug, it is pointless for me to treat it as a bug.



> Now, a goto-related regression has recently been reported for joiner:
>
> https://issues.dlang.org/show_bug.cgi?id=19213
>
> where some code worked with joiner in 2.081.2 but does not work with 2.082.0 or later, so you may want to test your code with an older compiler release to see if you've hit a compiler regression. If so, that could be a starting point for tracking down the problem.
>

Until I can simplify the code I have, it won't matter. If it is the same bug, then it will get fixed when it gets fixed with joiner. If it is a different bug, then it will get fixed with I can produce a test case.

While I could prove that it is a version issue by trying a different compiler version(I guess I should keep an old one around for that purpose) it seems it is likely that it is the same bug...






November 07, 2018
On Wednesday, November 7, 2018 10:50:29 PM MST Michelle Long via Digitalmars-d-learn wrote:
> On Thursday, 8 November 2018 at 02:22:42 UTC, Jonathan M Davis
>
> wrote:
> > On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via
> >
> > Digitalmars- d-learn wrote:
> >> Don't let their psychobabble fool you. They are wrong and you were right from the start.
> >
> > ...
> >
> >> Case A:
> >> {
> >>
> >>     if (true) goto X;
> >>     int x;
> >>
> >> }
> >> X:
> >>
> >>
> >> Case B:
> >> {
> >>
> >>     if (true) goto X;
> >>     {
> >>
> >>        int x;
> >>
> >>     }
> >>
> >> }
> >> X:
> >>
> >>
> >> These two cases are EXACTLY the same semantically. It's like
> >> writing A + B and (A + B).
> >
> > That's not the situation that the OP was describing. If adding braces in a situation where the braces have no semantic effect has any impact on goto, then it's a compiler bug. It's adding a new scope that affects the lifetime of a variable whose declaration is being jumped over by a goto that matters.
> >
> > I know that you're frustrated, because you've hit a problem with goto in complex code, and you don't have a simple example that shows the compiler bug, but the approach that D takes with goto (and any construct that potentially requires code flow analysis) of avoiding requiring that the compiler be smart is precisely to reduce the risk of there being cases where the compiler is going to screw it up in complex code even though it gets it right in the simple cases. If the language required the compiler to be smart about such things, we'd have a lot more problems with subtle, hard to track down compiler bugs in complex code. So, we'd just have _more_ cases where people would be hitting frustrating bugs like you are.
>
> That's fine. The D compiler writers can decide to do whatever they want. I can simply take my "business" elsewhere if I don't like it.
>
> What I am talking about is about an obvious error(Ok, I haven't produced a simplified test case but dustmite or visual D is not working for me to do so at this point in time, but it would be nice for sake of argument to assume I'm right...).
>
> > Regardless, if you want to actually have your problem fixed, you're going to need to provide a reproducible test case in a bugzilla report, even if it's large, otherwise no one is going to be able to track it down for you.
>
> That's easier said than done. I wasn't expecting anyone to be able to fix a bug that can't be reproduced.
>
> What I expect is that, given my assumptions that I'm right, that people can agree the compiler does have a bug or flaw that can easily be fixed give then two simplified test cases basic purely what I have done in my own code.
>
> 1.
>
> foreach(...)
> {
>    if (x) goto Y:
>    int z;
> }
> Y:
>
> Fails.
>
> foreach(...)
> {
>    if (x) goto Y:
>    {
>       int z;
>    }
> }
> Y:
>
> Passes.
>
> THAT IS FACT! It doesn't matter if the examples work above. I have simplified what I have done and in my code I simply add brackets and it works! That is what people should be thinking about... not test cases, MWE's, compiler versions, etc.
>
> Is it logical that the compiler **should** error out in the first case and no in the second?
>
> That is what the discussion is ALL about. Once that is dealt with then we can move on to finding out more specifics. There is no reason to build the windows of a house before the foundation, it's just far more work without any benefit.
>
>
> Once people can say: If that is all you are doing is adding brackets around what follows the goto and break out of scope(which is what the code above says) and you can compile, then it is a compiler bug or flaw.
>
> Once people verify that, rather than trying to create rabbit holes, then I can do more work on finding out more specifics. Until then, it is pointless to do anything on my side because if people come back and say "No, it is suppose to work that way" then what the hell am I trying to simplify and fix? It's not a bug then.

If you have code where you get a compiler error about a goto skipping the initializiation of a variable, and you add braces that should have no semantic effect on the code whatsoever, and the error goes away, then yes, that's a compiler bug. If, however, the braces do affect the semantics of the code, then that's not necessarily a compiler bug. At that point, whether it's a compiler bug or not would depend on what exactly the code was.

In an example such as

while(1)
{
    if(cond)
        goto label;
    int x;
}
label:

adding braces such as

while(1)
{
    if(cond)
    {
        goto label;
    }
    int x;
}
label:

or

while(1)
{
    if(cond)
        goto label;
    {
        int x;
    }
}
label:

should have no effect. However, in an example such as

goto label;
int x;
label:

adding braces such as

goto label;
{
    int x;
}
label:

changes the code entirely. It puts the variable x in a new scope such that it no longer exists at the label, and as such, its entire existence is skipped.

Braces matter for gotos because of how they affect scopes. If they're placed in a way that they don't affect scope, then they should have no effect on gotos. If they do affect scopes, then they can affect gotos, but whether they do or not is going to depend on the code. The key thing is that gotos cannot skip over the initialization of variables such that at the label, a variable now exists that did not exist at the goto. Variables can be skipped which would have come into scope and then left scope, but any declarations for variables which have not left scope are not allowed between the goto and the label. Braces can obviously affect that, and so braces can matter a great deal. But braces can also be used in ways that are optional, and if the braces are optional, then they don't affect scope, and they should have no effect on gotos.

> But what it seems is that people cannot reason about the purely theoretical underpinnings of the problem and need proof that there is even a problem in the first place, as if I'm making it up and then they create all kinds of obfuscation that doesn't help anyone.
>
> If you can agree that removing the brackets in the two test cases should work in ALL regular cases then I can attempt to provide more information.
>
> Again, until then, it is pointless. I could waste 10 hours trying to track the issue down to provide a test case and you can just come back and say "Oh, no, that is not a bug, it's suppose to be that way. We will not change anything". I know from previous history that is the typical mentality.
>
> Until We can agree that it is a bug, it is pointless for me to treat it as a bug.

Honestly, without seeing actual code that reproduces the problem, it's very difficult for any of us to accurately tell you whether you're seeing a bug or not. We can try to explain the language rules, and we can say whether we think what we're seeing is a bug based on what you describe, but with how easy it often is to misunderstand a problem when you have the actual code in front of you to study, dealing with everything second hand is bound to be a flawed process. I know that such situations can be very frustrating, but it is going to be very difficult for us to give you a definitive answer.

I can tell you that if adding braces which should have zero semantic effect on the code makes the error about skipping a variable's initialization with goto go away, then it definitely sounds like you found a compiler bug. But otherwise, I have no way of knowing without an actual piece of code that exhibits the problem, and regardless, without an actual piece of code that exhibits the problem, the compiler devs won't be able to fix anything.

> > Now, a goto-related regression has recently been reported for joiner:
> >
> > https://issues.dlang.org/show_bug.cgi?id=19213
> >
> > where some code worked with joiner in 2.081.2 but does not work with 2.082.0 or later, so you may want to test your code with an older compiler release to see if you've hit a compiler regression. If so, that could be a starting point for tracking down the problem.
>
> Until I can simplify the code I have, it won't matter. If it is the same bug, then it will get fixed when it gets fixed with joiner. If it is a different bug, then it will get fixed with I can produce a test case.
>
> While I could prove that it is a version issue by trying a different compiler version(I guess I should keep an old one around for that purpose) it seems it is likely that it is the same bug...

Well, if an older version of the compiler works for you, it at least lets you work around the problem for now even if it doesn't actually fix your problem long term, and someone _has_ produced a reduced example for that bug report, so if you have the same problem, it should be only a matter of time before your problem is fixed. Also, if it turns out that an older compiler version works for you, but it's a different problem, then it would be possible (albeit a bit of work) to figure out which commit broke your code, which would go long way to finding a fix. If an older compiler version doesn't work for you, then it doesn't really help you, but at least you then know that whatever problem you're hitting is not the same as that bug report.

- Jonathan M Davis



November 08, 2018
On Thursday, 8 November 2018 at 06:56:14 UTC, Jonathan M Davis wrote:
> On Wednesday, November 7, 2018 10:50:29 PM MST Michelle Long via Digitalmars-d-learn wrote:
>> On Thursday, 8 November 2018 at 02:22:42 UTC, Jonathan M Davis
>>
>> wrote:
>> > On Wednesday, November 7, 2018 1:03:47 PM MST Michelle Long via
>> >
>> > Digitalmars- d-learn wrote:
>> >> Don't let their psychobabble fool you. They are wrong and you were right from the start.
>> >
>> > ...
>> >
>> >> Case A:
>> >> {
>> >>
>> >>     if (true) goto X;
>> >>     int x;
>> >>
>> >> }
>> >> X:
>> >>
>> >>
>> >> Case B:
>> >> {
>> >>
>> >>     if (true) goto X;
>> >>     {
>> >>
>> >>        int x;
>> >>
>> >>     }
>> >>
>> >> }
>> >> X:
>> >>
>> >>
>> >> These two cases are EXACTLY the same semantically. It's like
>> >> writing A + B and (A + B).
>> >
>> > That's not the situation that the OP was describing. If adding braces in a situation where the braces have no semantic effect has any impact on goto, then it's a compiler bug. It's adding a new scope that affects the lifetime of a variable whose declaration is being jumped over by a goto that matters.
>> >
>> > I know that you're frustrated, because you've hit a problem with goto in complex code, and you don't have a simple example that shows the compiler bug, but the approach that D takes with goto (and any construct that potentially requires code flow analysis) of avoiding requiring that the compiler be smart is precisely to reduce the risk of there being cases where the compiler is going to screw it up in complex code even though it gets it right in the simple cases. If the language required the compiler to be smart about such things, we'd have a lot more problems with subtle, hard to track down compiler bugs in complex code. So, we'd just have _more_ cases where people would be hitting frustrating bugs like you are.
>>
>> That's fine. The D compiler writers can decide to do whatever they want. I can simply take my "business" elsewhere if I don't like it.
>>
>> What I am talking about is about an obvious error(Ok, I haven't produced a simplified test case but dustmite or visual D is not working for me to do so at this point in time, but it would be nice for sake of argument to assume I'm right...).
>>
>> > Regardless, if you want to actually have your problem fixed, you're going to need to provide a reproducible test case in a bugzilla report, even if it's large, otherwise no one is going to be able to track it down for you.
>>
>> That's easier said than done. I wasn't expecting anyone to be able to fix a bug that can't be reproduced.
>>
>> What I expect is that, given my assumptions that I'm right, that people can agree the compiler does have a bug or flaw that can easily be fixed give then two simplified test cases basic purely what I have done in my own code.
>>
>> 1.
>>
>> foreach(...)
>> {
>>    if (x) goto Y:
>>    int z;
>> }
>> Y:
>>
>> Fails.
>>
>> foreach(...)
>> {
>>    if (x) goto Y:
>>    {
>>       int z;
>>    }
>> }
>> Y:
>>
>> Passes.
>>
>> THAT IS FACT! It doesn't matter if the examples work above. I have simplified what I have done and in my code I simply add brackets and it works! That is what people should be thinking about... not test cases, MWE's, compiler versions, etc.
>>
>> Is it logical that the compiler **should** error out in the first case and no in the second?
>>
>> That is what the discussion is ALL about. Once that is dealt with then we can move on to finding out more specifics. There is no reason to build the windows of a house before the foundation, it's just far more work without any benefit.
>>
>>
>> Once people can say: If that is all you are doing is adding brackets around what follows the goto and break out of scope(which is what the code above says) and you can compile, then it is a compiler bug or flaw.
>>
>> Once people verify that, rather than trying to create rabbit holes, then I can do more work on finding out more specifics. Until then, it is pointless to do anything on my side because if people come back and say "No, it is suppose to work that way" then what the hell am I trying to simplify and fix? It's not a bug then.
>
> If you have code where you get a compiler error about a goto skipping the initializiation of a variable, and you add braces that should have no semantic effect on the code whatsoever, and the error goes away, then yes, that's a compiler bug. If, however, the braces do affect the semantics of the code, then that's not necessarily a compiler bug. At that point, whether it's a compiler bug or not would depend on what exactly the code was.
>
> In an example such as
>
> while(1)
> {
>     if(cond)
>         goto label;
>     int x;
> }
> label:
>
> adding braces such as
>
> while(1)
> {
>     if(cond)
>     {
>         goto label;
>     }
>     int x;
> }
> label:
>
> or
>
> while(1)
> {
>     if(cond)
>         goto label;
>     {
>         int x;
>     }
> }
> label:
>
> should have no effect. However, in an example such as
>
> goto label;
> int x;
> label:
>
> adding braces such as
>
> goto label;
> {
>     int x;
> }
> label:
>
> changes the code entirely.

Obviously, but that is not the case I mentioned. You can assume that I know how scopes work. No need to assume everyone that shows two cases that you have to bring up an unrelated case as a potential cause unless it is relevant.

Remember, I'm showing the starting case that has the bug and the final case that doesn't... it is simply "mental dustmite" on the code I have.

You shouldn't assume everyone can't comprehend such trivialities.

If a person cannot understand scope then I doubt they understand goto's... and definitely not that adding braces should not change the compiler behavior.

What happens when you do that you just create noise that makes it more difficult to have a proper discussion that gets at the whole point of the conversation.

You seem to default to assuming that the person you are talking to has no clue about the problem at hand. You might not do it intentionally but it is wrong to assume that because it almost never helps.

November 08, 2018
On Thursday, November 8, 2018 2:34:34 AM MST Michelle Long via Digitalmars- d-learn wrote:
> Obviously, but that is not the case I mentioned. You can assume that I know how scopes work. No need to assume everyone that shows two cases that you have to bring up an unrelated case as a potential cause unless it is relevant.
>
> Remember, I'm showing the starting case that has the bug and the final case that doesn't... it is simply "mental dustmite" on the code I have.
>
> You shouldn't assume everyone can't comprehend such trivialities.
>
> If a person cannot understand scope then I doubt they understand goto's... and definitely not that adding braces should not change the compiler behavior.
>
> What happens when you do that you just create noise that makes it more difficult to have a proper discussion that gets at the whole point of the conversation.
>
> You seem to default to assuming that the person you are talking to has no clue about the problem at hand. You might not do it intentionally but it is wrong to assume that because it almost never helps.

If you fully understood the situation, you wouldn't be asking whether your case was a compiler bug or not, and I don't know which parts you do and don't understand. So, I tried to be thorough in explaining the situation. And yes, by being thorough, I'm more likely to cover information that you already know and understand, but I'm also more likely to cover the information that you actually need. In order to avoid repeating anything you already understand and only tell you exactly what you need to know, I would have to somehow understand exactly which piece of the puzzle it is you're missing, and I don't.

Honestly, that rarely seems to be easy to do, and for whatever reason, it seems to be even harder to do than normal when discussing this issue with you. It seems like most of the discussion of this issue between you and various folks has been people talking passed each other without really coming to an understanding, which always makes for a frustrating discussion.

I'd like to help, but I don't know what else I can say. I've tried to explain how braces interact with goto and why, so you should be able to figure out whether you're dealing with a compiler bug or not. And if you are, unless you're dealing with one that someone else already has found independently and reported with a test case, somehow, you're going to need to reduce it enough to be able to create a bug report with an example if you want it fixed. A small example would be nice, but even a large example would be better than nothing. Either way, ultimately, without a reproducible test case, compiler bugs almost never get fixed. It just isn't practical for the compiler devs to track down bugs based on vague bug reports, even if they'd like to be helpful.

- Jonathan M Davis