Is this an error or undefined behaviour?

F

Franz Hose

the following program, when compiled with gcc and '-std=c99', gcc says

test.c:6: error: jump into scope of identifier with
variably modified type

that is, it does not even compile.

lcc-win32, on the other hand, reports

Warning test.c: 7 unreachable code

the resulting program crashes at runtime, but I guess that can be
expected because x is probably uninitialized (UB?)


My question is, is the below program invalid or is undefined
behaviour invoked?

--------------------------------------------------
#include <stdio.h>


void func1(int n)
{
goto label;
int x[n];
label:
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

int main(void)
{
func1(5);

return 0;
}
--------------------------------------------------
 
J

James Kuyper

Franz Hose wrote:
....
My question is, is the below program invalid or is undefined
behaviour invoked?

--------------------------------------------------
#include <stdio.h>


void func1(int n)
{
goto label;
int x[n];
label:
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

Section 6.8.6.1p1: "A goto statement shall not jump from outside the
scope of an identifier having a variably modified type to inside the
scope of that identifier." This occurs within a constraint, so a
diagnostic message is mandatory. I would say that the standard doesn't
specify what happens if you do violate that constraint, so it is
undefined behavior "by the omission of any explicit definition of the
behavior".

However, deriving UB from omission is always a tricky argument - it's
possible that something said elsewhere in the standard provides the
definition that seems to have been omitted.
 
?

=?iso-2022-kr?q?=1B=24=29CHarald_van_D=0E=29=26=0F

I would say that the standard doesn't
specify what happens if you do violate that constraint, so it is
undefined behavior "by the omission of any explicit definition of the
behavior".

However, deriving UB from omission is always a tricky argument - it's
possible that something said elsewhere in the standard provides the
definition that seems to have been omitted.

If a constraint is violated, and an implementation accepts the program
anyway, what happens when you run it is not within the scope of the
standard. Implementations are explicitly allowed to provide extensions
that don't alter the behaviour of strictly conforming programs.
Extensions that define the behaviour of constraint violations can't alter
the behaviour of strictly conforming programs, nor do they violate other
parts of the standard.
 
J

James Kuyper

Harald said:
If a constraint is violated, and an implementation accepts the program
anyway, what happens when you run it is not within the scope of the
standard.
>
Implementations are explicitly allowed to provide extensions
that don't alter the behaviour of strictly conforming programs.
Extensions that define the behaviour of constraint violations can't alter
the behaviour of strictly conforming programs, nor do they violate other
parts of the standard.

The standard doesn't apply just to strictly conforming programs. If the
program is not strictly conforming because of undefined behavior, then
all bets are off. If it contains a syntax error or a constraint
violation, or exceeds an implementation limit, then an implementation is
allowed to reject it. However, an implementation which accepts code that
doesn't have undefined behavior is required to translate and execute it
in a way that conforms to all applicable requirements of the standard,
even if the program isn't strictly conforming.

Conforming implementations are allowed to extend the C language, but
only if the extension is enabled by a construct which renders the
behavior of the program undefined by the C standard.
 
K

Keith Thompson

James Kuyper said:
The standard doesn't apply just to strictly conforming programs. If
the program is not strictly conforming because of undefined behavior,
then all bets are off. If it contains a syntax error or a constraint
violation, or exceeds an implementation limit, then an implementation
is allowed to reject it. However, an implementation which accepts code
that doesn't have undefined behavior is required to translate and
execute it in a way that conforms to all applicable requirements of
the standard, even if the program isn't strictly conforming.

Conforming implementations are allowed to extend the C language, but
only if the extension is enabled by a construct which renders the
behavior of the program undefined by the C standard.

My understanding is that any program that violates a constraint
invokes undefined behavior (assuming that the behavior isn't
documented, as an extension, by the implementation).

For example:

int main(void)
{
struct { int x; int y; } obj = 42;
return 0;
}

The attempt to initialize a struct object with an integer constant is
a constraint violation, and the compiler is allowed to reject the
program. Are you arguing that, if the compiler chooses to compile
this program, its behavior is defined? How?

A "constraint" is defined (C99 3.8) as a

restriction, either syntactic or semantic, by which the exposition
of language elements is to be interpreted

If such a restriction is violated, how can the program be correctly
interpreted?

A more common example is initializing a pointer with an integer
constant, something allowed by some compilers. This commonly causes
the integer value to be implicitly converted to the pointer type, but
nothing in the standard requires this.
 
G

Guest

James said:
The standard doesn't apply just to strictly conforming programs.

Right, it also applies to "correct" programs (programs which contain
no syntax errors, constraint violations, or undefined behaviour, if I
haven't missed anything): 4p3 requires those to be accepted and
translated correctly.
If the
program is not strictly conforming because of undefined behavior, then
all bets are off. If it contains a syntax error or a constraint
violation, or exceeds an implementation limit, then an implementation is
allowed to reject it. However, an implementation which accepts code that
doesn't have undefined behavior is required to translate and execute it
in a way that conforms to all applicable requirements of the standard,
even if the program isn't strictly conforming.

In other words, printf("%d\n", INT_MAX); must print the value of
INT_MAX, and isn't allowed to print "I don't want to print INT_MAX",
even though the output is implementation-defined.

However, do you know where the standard says that

int main(void) {
return 1. % 2.;
}

must either be rejected, or return 0? This is not a correct program,
so if an implementation chooses to accept it, 4p3 doesn't require it
to behave as suggested by the description of the % operator, and I
don't see any other paragraph that does. And real-world
implementations already do define the behaviour for what standard C
calls constraint violations, as extensions.
Conforming implementations are allowed to extend the C language, but
only if the extension is enabled by a construct which renders the
behavior of the program undefined by the C standard.

Which I believe constraint violations do. Well, almost. "Undefined
behaviour" means there are absolutely no requirements, while a
constraint violation requires at least some sort of diagnostic,
regardless of whether the behaviour is defined.
 
J

James Kuyper

Keith Thompson wrote:
....
My understanding is that any program that violates a constraint
invokes undefined behavior (assuming that the behavior isn't
documented, as an extension, by the implementation).

For example:

int main(void)
{
struct { int x; int y; } obj = 42;
return 0;
}

The attempt to initialize a struct object with an integer constant is
a constraint violation, and the compiler is allowed to reject the
program. Are you arguing that, if the compiler chooses to compile
this program, its behavior is defined? How?

A "constraint" is defined (C99 3.8) as a

restriction, either syntactic or semantic, by which the exposition
of language elements is to be interpreted

If such a restriction is violated, how can the program be correctly
interpreted?

I think that there are relatively few constraints which, when violated,
still leave a clear definition of what the behavior should be if an
implementation chooses to accept them, but I think that there are some.

I started searching for an example and came up with one that surprised
me. I'm looking at n1256.pdf, and found that it requires that the
operand of ++ be either real or a pointer. Why does it say 'real' rather
than 'arithmetic'? The ++ operator would pretty useless applied to an
imaginary type, but I don't see why there should be a problem with
complex types.

Whatever the reason for that constraint is, I believe that an
implementation which chooses to accept such code despite the fact that a
variable is complex, is required by 6.5.2.4p2 to implement it as adding
1 to the value of that variable.

The next example was more like what I expected: 6.5.3.2p1 - if an
implementation chooses to translate and execute code which attempts to
take the address of a variable declared with the 'register' keyword, I
believe it is still bound by 6.5.3.2p1, which would essentially mean
that it cannot place such a variable in a register. An implementation is
normally free to ignore a 'register' keyword - in this context, I think
that ignoring it becomes mandatory.

I'm not absolutely committed to this point of view; if the committee has
actually ruled on this issue, rejecting this interpretation, I'll accept
that. However, if violating a constraint always leaves the behavior
undefined behavior (except for the mandatory issuance of a diagnostic),
I think it would be clearer to say so explicitly.
 
K

Keith Thompson

James Kuyper said:
Keith Thompson wrote: [...]
A "constraint" is defined (C99 3.8) as a
restriction, either syntactic or semantic, by which the
exposition
of language elements is to be interpreted
If such a restriction is violated, how can the program be correctly
interpreted?

I think that there are relatively few constraints which, when
violated, still leave a clear definition of what the behavior should
be if an implementation chooses to accept them, but I think that there
are some.

I started searching for an example and came up with one that surprised
me. I'm looking at n1256.pdf, and found that it requires that the
operand of ++ be either real or a pointer. Why does it say 'real'
rather than 'arithmetic'? The ++ operator would pretty useless applied
to an imaginary type, but I don't see why there should be a problem
with complex types.

I think that applying ++ to a complex operand, though it could easily
be defined, just isn't useful enough to make it part of the language.
Similarly, "<<" and ">>" could be defined for floating-point and
complex types in terms of multiplication and division, but it's not
worth doing. In both cases, the primary usage would be in IOCCC
entries.
Whatever the reason for that constraint is, I believe that an
implementation which chooses to accept such code despite the fact that
a variable is complex, is required by 6.5.2.4p2 to implement it as
adding 1 to the value of that variable.

You may well be correct, but I'm going to disagree anyway. I think
the cases where the wording of a requirement applies even if a
constraint is violated are just coincidental. Stating the definition
of "++" so it explicitly doesn't apply to complex types would just
make it more verbose, to no real purpose.
The next example was more like what I expected: 6.5.3.2p1 - if an
implementation chooses to translate and execute code which attempts to
take the address of a variable declared with the 'register' keyword, I
believe it is still bound by 6.5.3.2p1, which would essentially mean
that it cannot place such a variable in a register. An implementation
is normally free to ignore a 'register' keyword - in this context, I
think that ignoring it becomes mandatory.

Quibble: any variable can be placed in a register (if it fits), at
least for part of its lifetime. It's a common optimization. But
that's beside the point.
I'm not absolutely committed to this point of view; if the committee
has actually ruled on this issue, rejecting this interpretation, I'll
accept that. However, if violating a constraint always leaves the
behavior undefined behavior (except for the mandatory issuance of a
diagnostic), I think it would be clearer to say so explicitly.

Agreed. I'm not sure whether this has been discussed in comp.std.c.
Unfortunately, "constraint violation" and "undefined behavior" aren't
great search terms. It won't hurt to ask again.
 
J

James Kuyper

Keith said:
I think that applying ++ to a complex operand, though it could easily
be defined, just isn't useful enough to make it part of the language.
Similarly, "<<" and ">>" could be defined for floating-point and
complex types in terms of multiplication and division, but it's not
worth doing. In both cases, the primary usage would be in IOCCC
entries.

I think that it is rarely the case, and arguably never the case, that it
is appropriate to apply ++ to a floating point number. However, if there
are any cases where it is appropriate for a real floating point
variable, there should be corresponding cases where it is appropriate
for a complex floating point variable.

....
 
R

Richard Tobin

James Kuyper said:
I think that it is rarely the case, and arguably never the case, that it
is appropriate to apply ++ to a floating point number.

Since there is a range of integer values that are guaranteed to be
exactly representable as doubles (and likewise for floats), it seems
reasonable to use doubles to store known-to-be-integer values if (for
example) you are going to pass them to library functions requiring
doubles. In that case, it also seems plausible to use the same idioms
for arithmetic that you would if they were ints.

I suppose the same could arise for complex numbers, but it's rather
less likely.

-- Richard
 
F

Franz Hose

James said:
Franz Hose wrote:
...
My question is, is the below program invalid or is undefined
behaviour invoked?

--------------------------------------------------
#include <stdio.h>


void func1(int n)
{
goto label;
int x[n];
label:
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

Section 6.8.6.1p1: "A goto statement shall not jump from outside the
scope of an identifier having a variably modified type to inside the
scope of that identifier." This occurs within a constraint, so a
diagnostic message is mandatory.

Well, lcc-win32 always prints a warning ("unreachable code"; is this
misleading?) even at the lowest warning level; so that part of the
standard should be satisfied.

[OT]
Looking at the generated code, internally,

int x[n];

is the roughly equivalent to

int *x = alloca(n * sizeof *x); /* allocate storage */
size_t hidden_sizeof_x = n*sizeof*x; /* what sizeof x evaluates to */

[/OT]

meaning, jumping over these leaves x unallocated as well as the
result of (sizeof x) indeterminate. When explicitly spelling out
the internal representation, I'd say it's U.B., but without that
knowledge, can the same still be said?

In a more complex example,

---------------------------------------
#include <stdio.h>

int blah = 1;

void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

int main(void)
{
func1(100);

return 0;
}
---------------------------------------

at the highest warning level it says (is this misleading?)

Warning test.c: 8 x is assigned a value that is never used

but by default no warning is issued.


and the program output is

size = 2122776232
<CRASH!> Unhandled page fault on write access to [...]


Should I file a bug report?
(I really like lcc-win32 because of its small size)

I would say that the standard doesn't
specify what happens if you do violate that constraint, so it is
undefined behavior "by the omission of any explicit definition of the
behavior".

However, deriving UB from omission is always a tricky argument - it's
possible that something said elsewhere in the standard provides the
definition that seems to have been omitted.

Or is the observed U.B. still standard conform?
 
J

James Kuyper

Franz said:
James said:
Franz Hose wrote:
...
My question is, is the below program invalid or is undefined
behaviour invoked?

--------------------------------------------------
#include <stdio.h>


void func1(int n)
{
goto label;
int x[n];
label:
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}
Section 6.8.6.1p1: "A goto statement shall not jump from outside the
scope of an identifier having a variably modified type to inside the
scope of that identifier." This occurs within a constraint, so a
diagnostic message is mandatory.

Well, lcc-win32 always prints a warning ("unreachable code"; is this
misleading?) even at the lowest warning level; so that part of the

That is not misleading; the code where x[n] is defined is unreachable,
and that is precisely the problem.
standard should be satisfied.

[OT]
Looking at the generated code, internally,

int x[n];

is the roughly equivalent to

int *x = alloca(n * sizeof *x); /* allocate storage */
size_t hidden_sizeof_x = n*sizeof*x; /* what sizeof x evaluates to */

[/OT]

meaning, jumping over these leaves x unallocated as well as the
result of (sizeof x) indeterminate. When explicitly spelling out
the internal representation, I'd say it's U.B., but without that
knowledge, can the same still be said?

I would say that the behavior is undefined, because the standard fails
to say what an expression involving a VLA means when the VLA hasn't
actually been created.
In a more complex example,

---------------------------------------
#include <stdio.h>

int blah = 1;

void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

int main(void)
{
func1(100);

return 0;
}
---------------------------------------

at the highest warning level it says (is this misleading?)

Warning test.c: 8 x is assigned a value that is never used

That message makes sense in terms of the replacement code using alloca()
above. However, the programmer never sees that replacement code, and in
terms of the actual code, that message makes no sense, and makes it more
difficult to figure out what the real problem is.
but by default no warning is issued.


and the program output is

size = 2122776232
<CRASH!> Unhandled page fault on write access to [...]


Should I file a bug report?

My understanding is that the program's output is acceptable, but that
the diagnostic message needs some improvement.

....
Or is the observed U.B. still standard conform?

That's a meaningless question. You can't observe UB, it isn't a
particular kind of behavior that, if it occurs, says "UB". UB can only
be deduced by comparison of a code sample with the standard. What UB
means, when it is correctly deduced, is that any behavior is permitted.

If my argument is correct, the behavior of this code is undefined, and
any behavior whatsoever is permitted to a conforming implementation of
C, including the <CRASH> above.

If my argument is incorrect, and the behavior is defined, then you need
to identify what the defined behavior is. In the unlikely case that the
defined behavior includes a crash, then the implementation is perfectly
conforming. :)
 
F

Flash Gordon

James Kuyper wrote, On 30/10/07 02:53:
Franz said:
James said:
Franz Hose wrote:
...
My question is, is the below program invalid or is undefined
behaviour invoked?

--------------------------------------------------
#include <stdio.h>


void func1(int n)
{
goto label;
int x[n];
label:
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}
Section 6.8.6.1p1: "A goto statement shall not jump from outside the
scope of an identifier having a variably modified type to inside the
scope of that identifier." This occurs within a constraint, so a
diagnostic message is mandatory.

Well, lcc-win32 always prints a warning ("unreachable code"; is this
misleading?) even at the lowest warning level; so that part of the

That is not misleading; the code where x[n] is defined is unreachable,
and that is precisely the problem.

I would consider it misleading because normally unreachable code is not
a constraint violation. It is, of course, conforming since the standard
does not place any requirements on what the diagnostic is.
standard should be satisfied.

[OT]
Looking at the generated code, internally,

int x[n];

is the roughly equivalent to

int *x = alloca(n * sizeof *x); /* allocate storage */
size_t hidden_sizeof_x = n*sizeof*x; /* what sizeof x evaluates to */

[/OT]

meaning, jumping over these leaves x unallocated as well as the result
of (sizeof x) indeterminate. When explicitly spelling out
the internal representation, I'd say it's U.B., but without that
knowledge, can the same still be said?

I would say that the behavior is undefined, because the standard fails
to say what an expression involving a VLA means when the VLA hasn't
actually been created.

The behaviour is undefined because there is a constraint violation since
the standard does not specify the behaviour if a constraint is violated
but an executable is produced anyway.
In a more complex example,
---------------------------------------
#include <stdio.h>

int blah = 1;

void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

int main(void)
{
func1(100);

return 0;
}
---------------------------------------

at the highest warning level it says (is this misleading?)

Warning test.c: 8 x is assigned a value that is never used

How about with the minimum warning level that claims conformance to C99?
A diagnostic is required at whatever warning level that is.
That message makes sense in terms of the replacement code using alloca()
above. However, the programmer never sees that replacement code, and in
terms of the actual code, that message makes no sense, and makes it more
difficult to figure out what the real problem is.

How about...
void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
}

int main(void)
{
func1(100);
return 0;
}

Or even:
void func1(int n)
{
if(n) goto label;
int x[n]; /* <== this is line 8 */
label:
return;
}

I believe a diagnostic is required for all of these.
but by default no warning is issued.


and the program output is

size = 2122776232
<CRASH!> Unhandled page fault on write access to [...]


Should I file a bug report?

My understanding is that the program's output is acceptable, but that
the diagnostic message needs some improvement.

Yes, although I suspect for at least one of the examples I've suggested
it might fail to produce a diagnostic and therefore not conform.

<snip>
 
F

Franz Hose

Flash said:
James Kuyper wrote, On 30/10/07 02:53:
Franz Hose wrote:
In a more complex example,
---------------------------------------
#include <stdio.h>

int blah = 1;

void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

int main(void)
{
func1(100);

return 0;
}
---------------------------------------

at the highest warning level it says (is this misleading?)

Warning test.c: 8 x is assigned a value that is never used

How about with the minimum warning level that claims conformance to C99?
A diagnostic is required at whatever warning level that is.
[snip]

How about...
void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
}

max. warnings:
$ make vlatest.exe
wine lc -ansic -A -shadows -unused -O -c vlatest.c -o vlatest.obj
Warning vlatest.c: 8 x is assigned a value that is never used
0 errors, 1 warning
wine lc vlatest.obj -o vlatest.exe -s -dynamic

default warnings:
$ make vlatest.exe
wine lc -ansic -O -c vlatest.c -o vlatest.obj
wine lc vlatest.obj -o vlatest.exe -s -dynamic
[no diagnostics]

$ wine vlatest
size = 2122665640
[no observable crash, but printed value is obviously bogus]

Or even:
void func1(int n)
{
if(n) goto label;
int x[n]; /* <== this is line 8 */
label:
return;
}

max. warnings:
$ make vlatest.exe
wine lc -ansic -A -shadows -unused -O -c vlatest.c -o vlatest.obj
Warning vlatest.c: 8 x is assigned a value that is never used
0 errors, 1 warning
wine lc vlatest.obj -o vlatest.exe -s -dynamic

default:
$ make vlatest.exe
wine lc -ansic -O -c vlatest.c -o vlatest.obj
wine lc vlatest.obj -o vlatest.exe -s -dynamic
[no diagnostics]

$ wine vlatest
[no output]
[no observable crash]
I believe a diagnostic is required for all of these.

That was my understanding as well.
Yes, although I suspect for at least one of the examples I've suggested
it might fail to produce a diagnostic and therefore not conform.

I don't have the final standard here at the moment, but found
an older thread on the same subject from August 2006,
msgid: <[email protected]> ,
and in one of the followups it is argued by Jacob that...

|
| The standard does not specify that a diagnostic is required in this
| case.
|
| The wording is:
|
| EXAMPLE 2 A goto statement is not allowed to jump past any declarations
| of objects with variably modified types. A jump within the scope,
| however, is permitted.
|
[my understanding of the standard is that an object's scope begins at the
point of the its declaration, not the beginning of the block, but IANAL]

|
| Maybe a language lawyer could help us here. If a diagnostic is required
| I will issue a diagnostic of course and this is a bug in lcc-win32 that
| will be corrected no matter what.
|
| jacob
|
[unfortunately there are no further followups to this question]
 
F

Flash Gordon

Franz Hose wrote, On 01/11/07 00:22:
Flash said:
James Kuyper wrote, On 30/10/07 02:53:
Franz Hose wrote:
In a more complex example,
---------------------------------------
#include <stdio.h>

int blah = 1;

void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
x[0] = 42;
printf("x[0] = %d\n", x[0]);
}

int main(void)
{
func1(100);

return 0;
}
---------------------------------------

at the highest warning level it says (is this misleading?)

Warning test.c: 8 x is assigned a value that is never used
How about with the minimum warning level that claims conformance to C99?
A diagnostic is required at whatever warning level that is.
[snip]

How about...
void func1(int n)
{
if(blah) goto label;
int x[n]; /* <== this is line 8 */
label:
printf("size = %lu\n", (unsigned long)sizeof x);
}

default warnings:
$ make vlatest.exe
wine lc -ansic -O -c vlatest.c -o vlatest.obj
wine lc vlatest.obj -o vlatest.exe -s -dynamic
[no diagnostics]

Then that is a bug in the compiler in my opinion.

Jacob, I think you need to put in specific checks for this. I think the
checks would be a good idea even for non-conforming modes because
obviously the code is not going "work" for most sensible values of "work".
$ wine vlatest
size = 2122665640
[no observable crash, but printed value is obviously bogus]

This does not surprise me.
Or even:
void func1(int n)
{
if(n) goto label;
int x[n]; /* <== this is line 8 */
label:
return;
}

max. warnings:
$ make vlatest.exe
wine lc -ansic -A -shadows -unused -O -c vlatest.c -o vlatest.obj
Warning vlatest.c: 8 x is assigned a value that is never used
0 errors, 1 warning
wine lc vlatest.obj -o vlatest.exe -s -dynamic

default:
$ make vlatest.exe
wine lc -ansic -O -c vlatest.c -o vlatest.obj
wine lc vlatest.obj -o vlatest.exe -s -dynamic
[no diagnostics]

$ wine vlatest
[no output]
[no observable crash]
I believe a diagnostic is required for all of these.

That was my understanding as well.

OK, we agree :)
I don't have the final standard here at the moment, but found

You can find drafts of the standard + TCs linked from
http://clc-wiki.net/wiki/c_standard
an older thread on the same subject from August 2006,
msgid: <[email protected]> ,
and in one of the followups it is argued by Jacob that...

|
| The standard does not specify that a diagnostic is required in this
| case.
|
| The wording is:
|
| EXAMPLE 2 A goto statement is not allowed to jump past any declarations
| of objects with variably modified types. A jump within the scope,
| however, is permitted.
|
[my understanding of the standard is that an object's scope begins at the
point of the its declaration, not the beginning of the block, but IANAL]

Well, try introducing a new block to avoid and ambiguity about the
presence of a bug...

void func1(int n)
{
if(n) goto label;
{
int x[n];
label:
return;
}
}

Or variants there of.
|
| Maybe a language lawyer could help us here. If a diagnostic is required
| I will issue a diagnostic of course and this is a bug in lcc-win32 that
| will be corrected no matter what.
|
| jacob
|
[unfortunately there are no further followups to this question]

Looking at the thread in Google
http://groups.google.co.uk/group/co...2e30a34ee04/717c5980b3bdc71d#717c5980b3bdc71d
I see a follow up by Rober Gamble to the original post stating that a
diagnostic is required.
http://groups.google.co.uk/group/comp.lang.c/msg/faec5cdaa815c9f9?dmode=source
Message ID <[email protected]>

Jacob, this was not a reply to your post asking for answers from
language lawyers, but it answers your question so I think you need to do
as your promised and make the compiler produce a diagnostic. Personally
I think the diagnostic should be produced in default mode, but as long
as it is produced in conforming mode that is all you need to conform.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,069
Latest member
SimplyleanKetoReviews

Latest Threads

Top