Reapply "[Parse] Use CapturedStmt for @finally on MSVC"
This reapplies r334224 and adds explicit triples to some tests to fix
them on Windows (where otherwise they would have run with the default
windows-msvc triple, which I'm changing the behavior for).
Original commit message:
The body of a `@finally` needs to be executed on both exceptional and
non-exceptional paths. On landingpad platforms, this is straightforward:
the `@finally` body is emitted as a normal (non-exceptional) cleanup,
and then a catch-all is emitted which branches to that cleanup (the
cleanup has code to conditionally re-throw based on a flag which is set
by the catch-all).
Unfortunately, we can't use the same approach for MSVC exceptions, where
the catch-all will be emitted as a catchpad. We can't just branch to the
cleanup from within the catchpad, since we can only exit it via a
catchret, at which point the exception is destroyed and we can't
rethrow. We could potentially emit the finally body inside the catchpad
and have the normal cleanup path somehow branch into it, but that would
require some new IR construct that could branch into a catchpad.
Instead, after discussing it with Reid Kleckner, we decided that
frontend outlining was the best approach, similar to how SEH `__finally`
works today. We decided to use CapturedStmt (which was also suggested by
Reid) rather than CaptureFinder (which is what `__finally` uses) since
the latter doesn't handle a lot of cases we care about, e.g. self
accesses, property accesses, block captures, etc. Extending
CaptureFinder to handle those additional cases proved unwieldy, whereas
CapturedStmt already took care of all of those. In theory `__finally`
could also be moved over to CapturedStmt, which would remove some
existing limitations (e.g. the inability to capture this), although
CaptureFinder would still be needed for SEH filters.
The one case supported by `@finally` but not CapturedStmt (or
CaptureFinder for that matter) is arbitrary control flow out of the
`@finally`, e.g. having a return statement inside a `@finally`. We can
add that support as a follow-up, but in practice we've found it to be
used very rarely anyway.
Differential Revision: https://reviews.llvm.org/D47564
llvm-svn: 334251
2018-06-08 08:30:00 +08:00
|
|
|
// RUN: %clang_cc1 -triple x86_64-apple-macosx10.10 -fsyntax-only -verify -fobjc-exceptions -Wno-objc-root-class %s
|
2009-04-15 04:53:38 +08:00
|
|
|
|
|
|
|
@class A, B, C;
|
|
|
|
|
2009-04-18 17:36:27 +08:00
|
|
|
void test1() {
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L; // expected-error{{cannot jump}}
|
|
|
|
goto L2; // expected-error{{cannot jump}}
|
|
|
|
goto L3; // expected-error{{cannot jump}}
|
2009-04-19 05:28:52 +08:00
|
|
|
@try { // expected-note {{jump bypasses initialization of @try block}}
|
2009-04-15 04:53:38 +08:00
|
|
|
L: ;
|
2009-04-19 05:28:52 +08:00
|
|
|
} @catch (A *x) { // expected-note {{jump bypasses initialization of @catch block}}
|
2009-04-15 04:53:38 +08:00
|
|
|
L2: ;
|
|
|
|
} @catch (B *x) {
|
|
|
|
} @catch (C *c) {
|
2009-04-19 05:28:52 +08:00
|
|
|
} @finally {// expected-note {{jump bypasses initialization of @finally block}}
|
2009-04-15 04:53:38 +08:00
|
|
|
L3: ;
|
|
|
|
}
|
2009-04-19 05:28:52 +08:00
|
|
|
|
|
|
|
@try {
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L4; // expected-error{{cannot jump}}
|
|
|
|
goto L5; // expected-error{{cannot jump}}
|
2009-04-19 05:28:52 +08:00
|
|
|
} @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
|
|
|
|
L5: ;
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L6; // expected-error{{cannot jump}}
|
2009-04-19 05:28:52 +08:00
|
|
|
} @catch (B *c) { // expected-note {{jump bypasses initialization of @catch block}}
|
|
|
|
L6: ;
|
|
|
|
} @finally { // expected-note {{jump bypasses initialization of @finally block}}
|
|
|
|
L4: ;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@try { // expected-note 2 {{jump bypasses initialization of @try block}}
|
|
|
|
L7: ;
|
|
|
|
} @catch (C *c) {
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L7; // expected-error{{cannot jump}}
|
2009-04-19 05:28:52 +08:00
|
|
|
} @finally {
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L7; // expected-error{{cannot jump}}
|
2009-04-19 05:28:52 +08:00
|
|
|
}
|
|
|
|
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L8; // expected-error{{cannot jump}}
|
2009-04-19 05:28:52 +08:00
|
|
|
@try {
|
2009-04-19 06:35:34 +08:00
|
|
|
} @catch (A *c) {
|
|
|
|
} @catch (B *c) {
|
2009-04-19 05:28:52 +08:00
|
|
|
} @catch (C *c) { // expected-note {{jump bypasses initialization of @catch block}}
|
|
|
|
L8: ;
|
|
|
|
}
|
2009-04-21 14:01:00 +08:00
|
|
|
|
|
|
|
// rdar://6810106
|
|
|
|
id X;
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L9; // expected-error{{cannot jump}}
|
2009-04-21 14:01:00 +08:00
|
|
|
goto L10; // ok
|
|
|
|
@synchronized // expected-note {{jump bypasses initialization of @synchronized block}}
|
|
|
|
( ({ L10: ; X; })) {
|
|
|
|
L9:
|
|
|
|
;
|
|
|
|
}
|
2009-04-15 04:53:38 +08:00
|
|
|
}
|
2009-04-15 22:38:36 +08:00
|
|
|
|
2009-04-18 17:36:27 +08:00
|
|
|
void test2(int a) {
|
2009-04-15 22:38:36 +08:00
|
|
|
if (a) goto L0;
|
|
|
|
@try {} @finally {}
|
|
|
|
L0:
|
|
|
|
return;
|
|
|
|
}
|
2009-04-18 17:36:27 +08:00
|
|
|
|
|
|
|
// rdar://6803963
|
|
|
|
void test3() {
|
|
|
|
@try {
|
|
|
|
goto blargh;
|
|
|
|
blargh: ;
|
|
|
|
} @catch (...) {}
|
|
|
|
}
|
2009-04-19 06:37:38 +08:00
|
|
|
|
|
|
|
@interface Greeter
|
|
|
|
+ (void) hello;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation Greeter
|
|
|
|
+ (void) hello {
|
|
|
|
|
|
|
|
@try {
|
2014-09-06 08:24:58 +08:00
|
|
|
goto blargh; // expected-error {{cannot jump}}
|
2009-04-19 06:37:38 +08:00
|
|
|
} @catch (...) { // expected-note {{jump bypasses initialization of @catch block}}
|
|
|
|
blargh: ;
|
|
|
|
}
|
|
|
|
}
|
2009-04-19 13:20:37 +08:00
|
|
|
|
|
|
|
+ (void)meth2 {
|
|
|
|
int n; void *P;
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L0; // expected-error {{cannot jump}}
|
2009-04-19 13:20:37 +08:00
|
|
|
typedef int A[n]; // expected-note {{jump bypasses initialization of VLA typedef}}
|
|
|
|
L0:
|
|
|
|
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L1; // expected-error {{cannot jump}}
|
2009-04-19 13:20:37 +08:00
|
|
|
A b, c[10]; // expected-note 2 {{jump bypasses initialization of variable length array}}
|
|
|
|
L1:
|
2014-09-06 08:24:58 +08:00
|
|
|
goto L2; // expected-error {{cannot jump}}
|
2009-04-19 13:20:37 +08:00
|
|
|
A d[n]; // expected-note {{jump bypasses initialization of variable length array}}
|
|
|
|
L2:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-04-19 06:37:38 +08:00
|
|
|
@end
|