blob: 09062bdea18947e93a59ab69cb15906de09e9b62 [file] [edit]
// REQUIRES: webassembly-registered-target
// RUN: %clang_cc1 -triple wasm32-unknown-emscripten -fobjc-exceptions -fexceptions -exception-model=wasm -mllvm -wasm-enable-eh -emit-llvm -fobjc-runtime=gnustep-2.2 -o - %s | FileCheck --enable-var-scope %s
__attribute__((objc_root_class)) @interface Object
@end
@interface ExceptionA : Object
@end
@interface ExceptionB : Object
@end
void mayThrow(void) {
@throw (id)1;
}
int basicCatchAll(void) {
@try {
mayThrow();
} @catch (...) {
return 1;
}
return 0;
}
// CHECK-LABEL: define{{.*}} @basicCatchAll
// CHECK: invoke void @mayThrow()
// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH:.*]]
// CHECK: [[CATCH_DISPATCH]]:
// CHECK-NEXT: [[CATCHSWITCH:%.*]] = catchswitch within none [label %[[CATCH_START:.*]]] unwind to caller
// CHECK: [[CATCH_START]]:
// CHECK-NEXT: [[CATCHPAD:%.*]] = catchpad within [[CATCHSWITCH]] [ptr null]
// CHECK: br label %[[CATCH_ALL:.*]]
// CHECK: [[INVOKE_CONT]]:
// CHECK: br label %[[EH_CONT:.*]]
// CHECK: [[CATCH_ALL]]:
// CHECK: call ptr @__cxa_begin_catch
// CHECK: call void @__cxa_end_catch()
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST:.*]]
// CHECK: [[CATCHRET_DEST]]:
// CHECK-NEXT: br label %return
int twoTypedHandlers(void) {
@try {
mayThrow();
} @catch (ExceptionA *exception) {
return 1;
} @catch (ExceptionB *exception) {
return 2;
}
return 0;
}
// CHECK-LABEL: define{{.*}} @twoTypedHandlers
// CHECK: invoke void @mayThrow()
// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH:.*]]
// CHECK: [[CATCH_DISPATCH]]:
// CHECK-NEXT: [[CATCHSWITCH:%.*]] = catchswitch within none [label %[[CATCH_START:.*]]] unwind to caller
// CHECK: [[CATCH_START]]:
// CHECK-NEXT: [[CATCHPAD:%.*]] = catchpad within [[CATCHSWITCH]] [ptr @__objc_eh_typeinfo_ExceptionA, ptr @__objc_eh_typeinfo_ExceptionB]
// CHECK: br i1 %{{.*}}, label %[[CATCH:.*]], label %[[CATCH_FALLTHROUGH:.*]]
// CHECK: [[CATCH_FALLTHROUGH]]:
// CHECK: br i1 %{{.*}}, label %[[CATCH2:.*]], label %[[RETHROW:.*]]
// CHECK: [[RETHROW]]:
// CHECK-NEXT: call void @llvm.wasm.rethrow()
// CHECK-NEXT: unreachable
// CHECK: [[INVOKE_CONT]]:
// CHECK: br label %[[EH_CONT:.*]]
// CHECK: [[EH_CONT]]:
// CHECK: br label %return
// CHECK: [[CATCH]]:
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST:.*]]
// CHECK: [[CATCHRET_DEST]]:
// CHECK-NEXT: br label %return
// CHECK: [[CATCH2]]:
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST2:.*]]
// CHECK: [[CATCHRET_DEST2]]:
// CHECK-NEXT: br label %return
int typedHandlerAndCatchAll(void) {
@try {
mayThrow();
} @catch (ExceptionA *exception) {
return 1;
} @catch (...) {
return 2;
}
return 0;
}
// CHECK-LABEL: define{{.*}} @typedHandlerAndCatchAll
// CHECK: invoke void @mayThrow()
// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH:.*]]
// CHECK: [[CATCH_DISPATCH]]:
// CHECK-NEXT: [[CATCHSWITCH:%.*]] = catchswitch within none [label %[[CATCH_START:.*]]] unwind to caller
// CHECK: [[CATCH_START]]:
// CHECK-NEXT: [[CATCHPAD:%.*]] = catchpad within [[CATCHSWITCH]] [ptr @__objc_eh_typeinfo_ExceptionA, ptr null]
// CHECK: br i1 %{{.*}}, label %[[CATCH:.*]], label %[[CATCH_ALL:.*]]
// CHECK: [[INVOKE_CONT]]:
// CHECK: br label %[[EH_CONT:.*]]
// CHECK: [[EH_CONT]]:
// CHECK: br label %return
// CHECK: [[CATCH]]:
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST:.*]]
// CHECK: [[CATCHRET_DEST]]:
// CHECK-NEXT: br label %return
// CHECK: [[CATCH_ALL]]:
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST_ALL:.*]]
// CHECK: [[CATCHRET_DEST_ALL]]:
// CHECK-NEXT: br label %return
int nestedTryCatch(void) {
@try {
@try {
mayThrow();
} @catch (ExceptionA *exception) {
return 1;
}
} @catch (...) {
return 2;
}
return 0;
}
// CHECK-LABEL: define{{.*}} @nestedTryCatch
// CHECK: invoke void @mayThrow()
// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH:.*]]
// CHECK: [[CATCH_DISPATCH]]:
// CHECK-NEXT: [[CATCHSWITCH:%.*]] = catchswitch within none [label %[[CATCH_START:.*]]] unwind label %[[CATCH_DISPATCH1:.*]]
// CHECK: [[CATCH_START]]:
// CHECK-NEXT: [[CATCHPAD:%.*]] = catchpad within [[CATCHSWITCH]] [ptr @__objc_eh_typeinfo_ExceptionA]
// CHECK: br i1 %{{.*}}, label %[[CATCH:.*]], label %[[RETHROW:.*]]
// CHECK: [[RETHROW]]:
// CHECK: invoke void @llvm.wasm.rethrow(){{.*}}[ "funclet"(token [[CATCHPAD]]) ]
// CHECK-NEXT: to label %[[UNREACHABLE:.*]] unwind label %[[CATCH_DISPATCH1]]
// CHECK: [[CATCH_DISPATCH1]]:
// CHECK-NEXT: [[CATCHSWITCH1:%.*]] = catchswitch within none [label %[[CATCH_START2:.*]]] unwind to caller
// CHECK: [[CATCH_START2]]:
// CHECK-NEXT: [[CATCHPAD1:%.*]] = catchpad within [[CATCHSWITCH1]] [ptr null]
// CHECK: [[INVOKE_CONT]]:
// CHECK: br label %[[EH_CONT:.*]]
// CHECK: [[EH_CONT]]:
// CHECK: br label %[[EH_CONT2:.*]]
// CHECK: [[EH_CONT2]]:
// CHECK: br label %return
// CHECK: [[CATCH]]:
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST:.*]]
// CHECK: [[CATCHRET_DEST]]:
// CHECK-NEXT: br label %return
// CHECK: [[CATCH_ALL:.*]]:
// CHECK: catchret from [[CATCHPAD1]] to label %[[CATCHRET_DEST_ALL:.*]]
// CHECK: [[CATCHRET_DEST_ALL]]:
// CHECK-NEXT: br label %return
int emptyCatch(void) {
@try {
mayThrow();
} @catch (ExceptionA *exception) {
}
return 0;
}
// CHECK-LABEL: define{{.*}} @emptyCatch
// CHECK: invoke void @mayThrow()
// CHECK-NEXT: to label %[[INVOKE_CONT:.*]] unwind label %[[CATCH_DISPATCH:.*]]
// CHECK: [[CATCH_DISPATCH]]:
// CHECK-NEXT: [[CATCHSWITCH:%.*]] = catchswitch within none [label %[[CATCH_START:.*]]] unwind to caller
// CHECK: [[CATCH_START]]:
// CHECK-NEXT: [[CATCHPAD:%.*]] = catchpad within [[CATCHSWITCH]] [ptr @__objc_eh_typeinfo_ExceptionA]
// CHECK: br i1 %{{.*}}, label %[[CATCH:.*]], label %[[RETHROW:.*]]
// CHECK: [[RETHROW]]:
// CHECK-NEXT: call void @llvm.wasm.rethrow()
// CHECK-NEXT: unreachable
// CHECK: [[INVOKE_CONT]]:
// CHECK: br label %[[EH_CONT:.*]]
// CHECK: [[EH_CONT]]:
// CHECK: [[CATCH]]:
// CHECK: catchret from [[CATCHPAD]] to label %[[CATCHRET_DEST:.*]]
// CHECK: [[CATCHRET_DEST]]:
// CHECK-NEXT: br label %[[EH_CONT]]
int explicitRethrow(void) {
@try {
mayThrow();
} @catch (...) {
@throw;
}
return 0;
}
// CHECK-LABEL: define{{.*}} @explicitRethrow
// CHECK: invoke void @mayThrow()
// CHECK-NEXT: to label %{{.*}} unwind label %[[CATCH_DISPATCH:.*]]
// CHECK: [[CATCH_DISPATCH]]:
// CHECK-NEXT: [[CATCHSWITCH:%.*]] = catchswitch within none [label %[[CATCH_START:.*]]] unwind to caller
// CHECK: [[CATCH_START]]:
// CHECK-NEXT: [[CATCHPAD:%.*]] = catchpad within [[CATCHSWITCH]] [ptr null]
// CHECK: br label %[[CATCH_ALL:.*]]
// CHECK: [[CATCH_ALL]]:
// CHECK: invoke void @__cxa_rethrow(){{.*}}[ "funclet"(token [[CATCHPAD]]) ]
// CHECK-NEXT: to label %[[UNREACHABLE:.*]] unwind label %{{.*}}
// CHECK: [[UNREACHABLE]]:
// CHECK-NEXT: unreachable