llvm-project/clang/test/Sema/scope-check.c
John McCall cf819ab383 When checking scopes for indirect goto, be more permissive (but still safe)
about the permitted scopes.  Specifically:
  1) Permit labels and gotos to appear after a prologue of variable initializations.
  2) Permit indirect gotos to jump out of scopes that don't require cleanup.
  3) Diagnose possible attempts to indirect-jump out of scopes that do require
     cleanup.
This requires a substantial reinvention of the algorithm for checking indirect
goto.  The current algorithm is Omega(M*N), with M = the number of unique
scopes being jumped from and N = the number of unique scopes being jumped to,
with an additional factor that is probably (worst-case) linear in the depth
of scopes.  Thus the entire thing is likely cubic given some truly bizarre
ill-formed code;  on well-formed code the additional factor collapses to
an amortized constant (when amortized over the entire function) and so
the algorithm is quadratic.  Even this requires every label to appear in
its own scope, which would be very unusual for indirect-goto code (and
extremely unlikely for well-formed code);  it is far more likely that
all labels will be in the same scope and so the algorithm becomes linear.
For such a marginal feature, I am fairly happy with this result.

(this is using JumpDiagnostic's definition of scope, where successive
variables in a block appear in their own scope)

llvm-svn: 103536
2010-05-12 00:58:13 +00:00

202 lines
5.0 KiB
C

// RUN: %clang_cc1 -fsyntax-only -verify -fblocks -std=gnu99 %s -Wno-unreachable-code
int test1(int x) {
goto L; // expected-error{{illegal goto into protected scope}}
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
int b[x]; // expected-note {{jump bypasses initialization of variable length array}}
L:
return sizeof a;
}
int test2(int x) {
goto L; // expected-error{{illegal goto into protected scope}}
typedef int a[x]; // expected-note {{jump bypasses initialization of VLA typedef}}
L:
return sizeof(a);
}
void test3clean(int*);
int test3() {
goto L; // expected-error{{illegal goto into protected scope}}
int a __attribute((cleanup(test3clean))); // expected-note {{jump bypasses initialization of declaration with __attribute__((cleanup))}}
L:
return a;
}
int test4(int x) {
goto L; // expected-error{{illegal goto into protected scope}}
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
test4(x);
L:
return sizeof a;
}
int test5(int x) {
int a[x];
test5(x);
goto L; // Ok.
L:
goto L; // Ok.
return sizeof a;
}
int test6() {
// just plain invalid.
goto x; // expected-error {{use of undeclared label 'x'}}
}
void test7(int x) {
switch (x) {
case 1: ;
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
case 2: // expected-error {{illegal switch case into protected scope}}
a[1] = 2;
break;
}
}
int test8(int x) {
// For statement.
goto L2; // expected-error {{illegal goto into protected scope}}
for (int arr[x]; // expected-note {{jump bypasses initialization of variable length array}}
; ++x)
L2:;
// Statement expressions.
goto L3; // expected-error {{illegal goto into protected scope}}
int Y = ({ int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
L3: 4; });
goto L4; // expected-error {{illegal goto into protected scope}}
{
int A[x], // expected-note {{jump bypasses initialization of variable length array}}
B[x]; // expected-note {{jump bypasses initialization of variable length array}}
L4: ;
}
{
L5: ;// ok
int A[x], B = ({ if (x)
goto L5;
else
goto L6;
4; });
L6:; // ok.
if (x) goto L6; // ok
}
{
L7: ;// ok
int A[x], B = ({ if (x)
goto L7;
else
goto L8; // expected-error {{illegal goto into protected scope}}
4; }),
C[x]; // expected-note {{jump bypasses initialization of variable length array}}
L8:; // bad
}
{
L9: ;// ok
int A[({ if (x)
goto L9;
else
// FIXME:
goto L10; // fixme-error {{illegal goto into protected scope}}
4; })];
L10:; // bad
}
{
// FIXME: Crashes goto checker.
//goto L11;// ok
//int A[({ L11: 4; })];
}
{
goto L12;
int y = 4; // fixme-warn: skips initializer.
L12:
;
}
// Statement expressions 2.
goto L1; // expected-error {{illegal goto into protected scope}}
return x == ({
int a[x]; // expected-note {{jump bypasses initialization of variable length array}}
L1:
42; });
}
void test9(int n, void *P) {
int Y;
int Z = 4;
goto *P; // expected-warning {{indirect goto might cross protected scopes}}
L2: ;
int a[n]; // expected-note {{jump bypasses initialization of variable length array}}
L3: // expected-note {{possible target of indirect goto}}
L4:
goto *P;
goto L3; // ok
goto L4; // ok
void *Ptrs[] = {
&&L2,
&&L3
};
}
void test10(int n, void *P) {
goto L0; // expected-error {{illegal goto into protected scope}}
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
L0:
goto L1; // expected-error {{illegal goto into protected scope}}
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
L1:
goto L2; // expected-error {{illegal goto into protected scope}}
A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
L2:
return;
}
void test11(int n) {
void *P = ^{
switch (n) {
case 1:;
case 2:
case 3:;
int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
case 4: // expected-error {{illegal switch case into protected scope}}
return;
}
};
}
// TODO: When and if gotos are allowed in blocks, this should work.
void test12(int n) {
void *P = ^{
goto L1;
L1:
goto L2;
L2:
goto L3; // expected-error {{illegal goto into protected scope}}
int Arr[n]; // expected-note {{jump bypasses initialization of variable length array}}
L3:
goto L4;
L4: return;
};
}
void test13(int n, void *p) {
int vla[n];
goto *p;
a0: ;
static void *ps[] = { &&a0 };
}