head	1.1;
branch	1.1.1;
access;
symbols
	netbsd-10-2-RELEASE:1.1.1.2
	netbsd-9-5-RELEASE:1.1.1.1
	netbsd-11-0-RELEASE:1.1.1.2
	netbsd-11-0-RC7:1.1.1.2
	netbsd-11-0-RC6:1.1.1.2
	netbsd-11-0-RC5:1.1.1.2
	netbsd-11-0-RC4:1.1.1.2
	netbsd-11-0-RC3:1.1.1.2
	netbsd-11-0-RC2:1.1.1.2
	netbsd-11-0-RC1:1.1.1.2
	perseant-exfatfs-base-20250801:1.1.1.2
	netbsd-11:1.1.1.2.0.10
	netbsd-11-base:1.1.1.2
	netbsd-10-1-RELEASE:1.1.1.2
	perseant-exfatfs-base-20240630:1.1.1.2
	perseant-exfatfs:1.1.1.2.0.8
	perseant-exfatfs-base:1.1.1.2
	netbsd-9-4-RELEASE:1.1.1.1
	netbsd-10-0-RELEASE:1.1.1.2
	netbsd-10-0-RC6:1.1.1.2
	netbsd-10-0-RC5:1.1.1.2
	netbsd-10-0-RC4:1.1.1.2
	netbsd-10-0-RC3:1.1.1.2
	netbsd-10-0-RC2:1.1.1.2
	netbsd-10-0-RC1:1.1.1.2
	netbsd-10:1.1.1.2.0.6
	netbsd-10-base:1.1.1.2
	netbsd-9-3-RELEASE:1.1.1.1
	cjep_sun2x:1.1.1.2.0.4
	cjep_sun2x-base:1.1.1.2
	cjep_staticlib_x-base1:1.1.1.2
	netbsd-9-2-RELEASE:1.1.1.1
	cjep_staticlib_x:1.1.1.2.0.2
	cjep_staticlib_x-base:1.1.1.2
	netbsd-9-1-RELEASE:1.1.1.1
	phil-wifi-20200421:1.1.1.2
	phil-wifi-20200411:1.1.1.2
	phil-wifi-20200406:1.1.1.2
	netbsd-9-0-RELEASE:1.1.1.1
	netbsd-9-0-RC2:1.1.1.1
	netbsd-9-0-RC1:1.1.1.1
	netbsd-9:1.1.1.1.0.6
	netbsd-9-base:1.1.1.1
	phil-wifi:1.1.1.1.0.4
	phil-wifi-20190609:1.1.1.1
	pgoyette-compat-merge-20190127:1.1.1.1.2.2
	pgoyette-compat-20190127:1.1.1.1
	pgoyette-compat-20190118:1.1.1.1
	pgoyette-compat-1226:1.1.1.1
	pgoyette-compat-1126:1.1.1.1
	pgoyette-compat-1020:1.1.1.1
	pgoyette-compat-0930:1.1.1.1
	pgoyette-compat-0906:1.1.1.1
	pgoyette-compat:1.1.1.1.0.2
	pgoyette-compat-0728:1.1.1.1
	clang-337282:1.1.1.1
	LLVM:1.1.1;
locks; strict;
comment	@// @;


1.1
date	2018.07.17.18.31.26;	author joerg;	state Exp;
branches
	1.1.1.1;
next	;
commitid	wDzL46ALjrCZgwKA;

1.1.1.1
date	2018.07.17.18.31.26;	author joerg;	state Exp;
branches
	1.1.1.1.2.1
	1.1.1.1.4.1;
next	1.1.1.2;
commitid	wDzL46ALjrCZgwKA;

1.1.1.2
date	2019.11.13.22.20.16;	author joerg;	state dead;
branches;
next	;
commitid	QD8YATxuNG34YJKB;

1.1.1.1.2.1
date	2018.07.17.18.31.26;	author pgoyette;	state dead;
branches;
next	1.1.1.1.2.2;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.1.2.2
date	2018.07.28.04.33.43;	author pgoyette;	state Exp;
branches;
next	;
commitid	1UP1xAIUxv1ZgRLA;

1.1.1.1.4.1
date	2018.07.17.18.31.26;	author christos;	state dead;
branches;
next	1.1.1.1.4.2;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.1.4.2
date	2019.06.10.21.45.52;	author christos;	state Exp;
branches;
next	1.1.1.1.4.3;
commitid	jtc8rnCzWiEEHGqB;

1.1.1.1.4.3
date	2020.04.13.07.47.29;	author martin;	state dead;
branches;
next	;
commitid	X01YhRUPVUDaec4C;


desc
@@


1.1
log
@Initial revision
@
text
@// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s

void may_throw();
void dont_throw() noexcept;

struct Cleanup {
  ~Cleanup() { dont_throw(); }
};

// Multiple catch clauses w/o catch-all
void test0() {
  try {
    may_throw();
  } catch (int) {
    dont_throw();
  } catch (double) {
    dont_throw();
  }
}

// CHECK-LABEL: define void @@_Z5test0v() {{.*}} personality i8* bitcast (i32 (...)* @@__gxx_wasm_personality_v0 to i8*)

// CHECK:   %[[INT_ALLOCA:.*]] = alloca i32
// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]

// CHECK: [[CATCHDISPATCH_BB]]:
// CHECK-NEXT:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* bitcast (i8** @@_ZTId to i8*)]
// CHECK-NEXT:   %[[EXN:.*]] = call i8* @@llvm.wasm.get.exception(token %[[CATCHPAD]])
// CHECK-NEXT:   store i8* %[[EXN]], i8** %exn.slot
// CHECK-NEXT:   %[[SELECTOR:.*]] = call i32 @@llvm.wasm.get.ehselector(token %[[CATCHPAD]])
// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @@llvm.eh.typeid.for(i8* bitcast (i8** @@_ZTIi to i8*)) #2
// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK-NEXT:   %[[EXN:.*]] = load i8*, i8** %exn.slot
// CHECK-NEXT:   %[[ADDR:.*]] = call i8* @@__cxa_begin_catch(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   %[[ADDR_CAST:.*]] = bitcast i8* %[[ADDR]] to i32*
// CHECK-NEXT:   %[[INT_VAL:.*]] = load i32, i32* %[[ADDR_CAST]]
// CHECK-NEXT:   store i32 %[[INT_VAL]], i32* %[[INT_ALLOCA]]
// CHECK-NEXT:   call void @@_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]]

// CHECK: [[CATCHRET_DEST_BB0]]:
// CHECK-NEXT:   br label %[[TRY_CONT_BB:.*]]

// CHECK: [[CATCH_FALLTHROUGH_BB]]
// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @@llvm.eh.typeid.for(i8* bitcast (i8** @@_ZTId to i8*)) #2
// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]

// CHECK: [[CATCH_FLOAT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]

// CHECK: [[CATCHRET_DEST_BB1]]:
// CHECK-NEXT:   br label %[[TRY_CONT_BB]]

// CHECK: [[RETHROW_BB]]:
// CHECK-NEXT:   call void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   unreachable

// Single catch-all
void test1() {
  try {
    may_throw();
  } catch (...) {
    dont_throw();
  }
}

// CATCH-LABEL: @@_Z5test1v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
// CHECK:   br label %[[CATCH_ALL_BB:.*]]

// CHECK: [[CATCH_ALL_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// Multiple catch clauses w/ catch-all
void test2() {
  try {
    may_throw();
  } catch (int) {
    dont_throw();
  } catch (...) {
    dont_throw();
  }
}

// CHECK-LABEL: @@_Z5test2v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* null]
// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// CHECK: [[CATCH_ALL_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// Cleanup
void test3() {
  Cleanup c;
  may_throw();
}

// CHECK-LABEL: @@_Z5test3v()

// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller

// Possibly throwing function call within a catch
void test4() {
  try {
    may_throw();
  } catch (int) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test4v()

// CHECK:   %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[INVOKE_CONT_BB]]:
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller

// Possibly throwing function call within a catch-all
void test5() {
  try {
    may_throw();
  } catch (...) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test5v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[INVOKE_CONT_BB0]]:
// CHECK-NEXT:   call void @@__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]]

// CHECK: [[INVOKE_CONT_BB1]]:
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind to caller

// CHECK: [[TERMINATE_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []
// CHECK-NEXT:   %[[EXN:.*]] = call i8* @@llvm.wasm.get.exception(token %[[CLEANUPPAD1]])
// CHECK-NEXT:   call void @@__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
// CHECK-NEXT:   unreachable

// CHECK-LABEL: define {{.*}} void @@__clang_call_terminate(i8*)
// CHECK-NEXT:   call i8* @@__cxa_begin_catch(i8* %{{.*}})
// CHECK-NEXT:   call void @@_ZSt9terminatev()
// CHECK-NEXT:   unreachable

// Try-catch with cleanups
void test6() {
  Cleanup c1;
  try {
    Cleanup c2;
    may_throw();
  } catch (int) {
    Cleanup c3;
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test6v()
// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]

// CHECK: [[EHCLEANUP_BB0]]:
// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]

// CHECK: [[CATCH_DISPATCH_BB]]:
// CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*)]
// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]

// CHECK: [[INVOKE_CONT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}

// CHECK: [[RETHROW_BB]]:
// CHECK-NEXT:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[EHCLEANUP_BB2]]:
// CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]

// CHECK: [[EHCLEANUP_BB3]]:
// CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[EHCLEANUP_BB1]]:
// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller

// CHECK: [[UNREACHABLE_BB]]:
// CHECK-NEXT:   unreachable

// Nested try-catches within a try with cleanups
void test7() {
  Cleanup c1;
  may_throw();
  try {
    Cleanup c2;
    may_throw();
    try {
      Cleanup c3;
      may_throw();
    } catch (int) {
      may_throw();
    } catch (double) {
      may_throw();
    }
  } catch (int) {
    may_throw();
  } catch (...) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test7v()
// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label

// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* bitcast (i8** @@_ZTId to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label

// CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label

// CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label

// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* null]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]

// CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label

// CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label

// CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller

// CHECK:   unreachable

// CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
// CHECK:   call void @@__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
// CHECK:   unreachable

// Nested try-catches within a catch
void test8() {
  try {
    may_throw();
  } catch (int) {
    try {
      may_throw();
    } catch (int) {
      may_throw();
    }
  }
}

// CHECK-LABEL: @@_Z5test8v()
// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]

// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   call void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
// CHECK:   unreachable

// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label

// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller

// CHECK:   unreachable
@


1.1.1.1
log
@Import clang r337282 from trunk
@
text
@@


1.1.1.2
log
@Mark old LLVM instance as dead.
@
text
@@


1.1.1.1.4.1
log
@file wasm-eh.cpp was added on branch phil-wifi on 2019-06-10 21:45:52 +0000
@
text
@d1 384
@


1.1.1.1.4.2
log
@Sync with HEAD
@
text
@a0 384
// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s

void may_throw();
void dont_throw() noexcept;

struct Cleanup {
  ~Cleanup() { dont_throw(); }
};

// Multiple catch clauses w/o catch-all
void test0() {
  try {
    may_throw();
  } catch (int) {
    dont_throw();
  } catch (double) {
    dont_throw();
  }
}

// CHECK-LABEL: define void @@_Z5test0v() {{.*}} personality i8* bitcast (i32 (...)* @@__gxx_wasm_personality_v0 to i8*)

// CHECK:   %[[INT_ALLOCA:.*]] = alloca i32
// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]

// CHECK: [[CATCHDISPATCH_BB]]:
// CHECK-NEXT:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* bitcast (i8** @@_ZTId to i8*)]
// CHECK-NEXT:   %[[EXN:.*]] = call i8* @@llvm.wasm.get.exception(token %[[CATCHPAD]])
// CHECK-NEXT:   store i8* %[[EXN]], i8** %exn.slot
// CHECK-NEXT:   %[[SELECTOR:.*]] = call i32 @@llvm.wasm.get.ehselector(token %[[CATCHPAD]])
// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @@llvm.eh.typeid.for(i8* bitcast (i8** @@_ZTIi to i8*)) #2
// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK-NEXT:   %[[EXN:.*]] = load i8*, i8** %exn.slot
// CHECK-NEXT:   %[[ADDR:.*]] = call i8* @@__cxa_begin_catch(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   %[[ADDR_CAST:.*]] = bitcast i8* %[[ADDR]] to i32*
// CHECK-NEXT:   %[[INT_VAL:.*]] = load i32, i32* %[[ADDR_CAST]]
// CHECK-NEXT:   store i32 %[[INT_VAL]], i32* %[[INT_ALLOCA]]
// CHECK-NEXT:   call void @@_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]]

// CHECK: [[CATCHRET_DEST_BB0]]:
// CHECK-NEXT:   br label %[[TRY_CONT_BB:.*]]

// CHECK: [[CATCH_FALLTHROUGH_BB]]
// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @@llvm.eh.typeid.for(i8* bitcast (i8** @@_ZTId to i8*)) #2
// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]

// CHECK: [[CATCH_FLOAT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]

// CHECK: [[CATCHRET_DEST_BB1]]:
// CHECK-NEXT:   br label %[[TRY_CONT_BB]]

// CHECK: [[RETHROW_BB]]:
// CHECK-NEXT:   call void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   unreachable

// Single catch-all
void test1() {
  try {
    may_throw();
  } catch (...) {
    dont_throw();
  }
}

// CATCH-LABEL: @@_Z5test1v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
// CHECK:   br label %[[CATCH_ALL_BB:.*]]

// CHECK: [[CATCH_ALL_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// Multiple catch clauses w/ catch-all
void test2() {
  try {
    may_throw();
  } catch (int) {
    dont_throw();
  } catch (...) {
    dont_throw();
  }
}

// CHECK-LABEL: @@_Z5test2v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* null]
// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// CHECK: [[CATCH_ALL_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// Cleanup
void test3() {
  Cleanup c;
  may_throw();
}

// CHECK-LABEL: @@_Z5test3v()

// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller

// Possibly throwing function call within a catch
void test4() {
  try {
    may_throw();
  } catch (int) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test4v()

// CHECK:   %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[INVOKE_CONT_BB]]:
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller

// Possibly throwing function call within a catch-all
void test5() {
  try {
    may_throw();
  } catch (...) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test5v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[INVOKE_CONT_BB0]]:
// CHECK-NEXT:   call void @@__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]]

// CHECK: [[INVOKE_CONT_BB1]]:
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind to caller

// CHECK: [[TERMINATE_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []
// CHECK-NEXT:   %[[EXN:.*]] = call i8* @@llvm.wasm.get.exception(token %[[CLEANUPPAD1]])
// CHECK-NEXT:   call void @@__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
// CHECK-NEXT:   unreachable

// CHECK-LABEL: define {{.*}} void @@__clang_call_terminate(i8*)
// CHECK-NEXT:   call i8* @@__cxa_begin_catch(i8* %{{.*}})
// CHECK-NEXT:   call void @@_ZSt9terminatev()
// CHECK-NEXT:   unreachable

// Try-catch with cleanups
void test6() {
  Cleanup c1;
  try {
    Cleanup c2;
    may_throw();
  } catch (int) {
    Cleanup c3;
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test6v()
// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]

// CHECK: [[EHCLEANUP_BB0]]:
// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]

// CHECK: [[CATCH_DISPATCH_BB]]:
// CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*)]
// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]

// CHECK: [[INVOKE_CONT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}

// CHECK: [[RETHROW_BB]]:
// CHECK-NEXT:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[EHCLEANUP_BB2]]:
// CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]

// CHECK: [[EHCLEANUP_BB3]]:
// CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[EHCLEANUP_BB1]]:
// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller

// CHECK: [[UNREACHABLE_BB]]:
// CHECK-NEXT:   unreachable

// Nested try-catches within a try with cleanups
void test7() {
  Cleanup c1;
  may_throw();
  try {
    Cleanup c2;
    may_throw();
    try {
      Cleanup c3;
      may_throw();
    } catch (int) {
      may_throw();
    } catch (double) {
      may_throw();
    }
  } catch (int) {
    may_throw();
  } catch (...) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test7v()
// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label

// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* bitcast (i8** @@_ZTId to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label

// CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label

// CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label

// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* null]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]

// CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label

// CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label

// CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller

// CHECK:   unreachable

// CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
// CHECK:   call void @@__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
// CHECK:   unreachable

// Nested try-catches within a catch
void test8() {
  try {
    may_throw();
  } catch (int) {
    try {
      may_throw();
    } catch (int) {
      may_throw();
    }
  }
}

// CHECK-LABEL: @@_Z5test8v()
// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]

// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   call void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
// CHECK:   unreachable

// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label

// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller

// CHECK:   unreachable
@


1.1.1.1.4.3
log
@Mostly merge changes from HEAD upto 20200411
@
text
@@


1.1.1.1.2.1
log
@file wasm-eh.cpp was added on branch pgoyette-compat on 2018-07-28 04:33:43 +0000
@
text
@d1 384
@


1.1.1.1.2.2
log
@Sync with HEAD
@
text
@a0 384
// RUN: %clang_cc1 %s -triple wasm32-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s
// RUN: %clang_cc1 %s -triple wasm64-unknown-unknown -fms-extensions -fexceptions -fcxx-exceptions -target-feature +exception-handling -emit-llvm -o - -std=c++11 | FileCheck %s

void may_throw();
void dont_throw() noexcept;

struct Cleanup {
  ~Cleanup() { dont_throw(); }
};

// Multiple catch clauses w/o catch-all
void test0() {
  try {
    may_throw();
  } catch (int) {
    dont_throw();
  } catch (double) {
    dont_throw();
  }
}

// CHECK-LABEL: define void @@_Z5test0v() {{.*}} personality i8* bitcast (i32 (...)* @@__gxx_wasm_personality_v0 to i8*)

// CHECK:   %[[INT_ALLOCA:.*]] = alloca i32
// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label %[[NORMAL_BB:.*]] unwind label %[[CATCHDISPATCH_BB:.*]]

// CHECK: [[CATCHDISPATCH_BB]]:
// CHECK-NEXT:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* bitcast (i8** @@_ZTId to i8*)]
// CHECK-NEXT:   %[[EXN:.*]] = call i8* @@llvm.wasm.get.exception(token %[[CATCHPAD]])
// CHECK-NEXT:   store i8* %[[EXN]], i8** %exn.slot
// CHECK-NEXT:   %[[SELECTOR:.*]] = call i32 @@llvm.wasm.get.ehselector(token %[[CATCHPAD]])
// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @@llvm.eh.typeid.for(i8* bitcast (i8** @@_ZTIi to i8*)) #2
// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_INT_BB:.*]], label %[[CATCH_FALLTHROUGH_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK-NEXT:   %[[EXN:.*]] = load i8*, i8** %exn.slot
// CHECK-NEXT:   %[[ADDR:.*]] = call i8* @@__cxa_begin_catch(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   %[[ADDR_CAST:.*]] = bitcast i8* %[[ADDR]] to i32*
// CHECK-NEXT:   %[[INT_VAL:.*]] = load i32, i32* %[[ADDR_CAST]]
// CHECK-NEXT:   store i32 %[[INT_VAL]], i32* %[[INT_ALLOCA]]
// CHECK-NEXT:   call void @@_Z10dont_throwv() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB0:.*]]

// CHECK: [[CATCHRET_DEST_BB0]]:
// CHECK-NEXT:   br label %[[TRY_CONT_BB:.*]]

// CHECK: [[CATCH_FALLTHROUGH_BB]]
// CHECK-NEXT:   %[[TYPEID:.*]] = call i32 @@llvm.eh.typeid.for(i8* bitcast (i8** @@_ZTId to i8*)) #2
// CHECK-NEXT:   %[[MATCHES:.*]] = icmp eq i32 %[[SELECTOR]], %[[TYPEID]]
// CHECK-NEXT:   br i1 %[[MATCHES]], label %[[CATCH_FLOAT_BB:.*]], label %[[RETHROW_BB:.*]]

// CHECK: [[CATCH_FLOAT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label %[[CATCHRET_DEST_BB1:.*]]

// CHECK: [[CATCHRET_DEST_BB1]]:
// CHECK-NEXT:   br label %[[TRY_CONT_BB]]

// CHECK: [[RETHROW_BB]]:
// CHECK-NEXT:   call void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   unreachable

// Single catch-all
void test1() {
  try {
    may_throw();
  } catch (...) {
    dont_throw();
  }
}

// CATCH-LABEL: @@_Z5test1v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]
// CHECK:   br label %[[CATCH_ALL_BB:.*]]

// CHECK: [[CATCH_ALL_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// Multiple catch clauses w/ catch-all
void test2() {
  try {
    may_throw();
  } catch (int) {
    dont_throw();
  } catch (...) {
    dont_throw();
  }
}

// CHECK-LABEL: @@_Z5test2v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* null]
// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[CATCH_ALL_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// CHECK: [[CATCH_ALL_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label

// Cleanup
void test3() {
  Cleanup c;
  may_throw();
}

// CHECK-LABEL: @@_Z5test3v()

// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label {{.*}} unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller

// Possibly throwing function call within a catch
void test4() {
  try {
    may_throw();
  } catch (int) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test4v()

// CHECK:   %[[CATCHSWITCH]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[INVOKE_CONT_BB]]:
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   call void @@__cxa_end_catch() {{.*}} [ "funclet"(token %[[CLEANUPPAD]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD]] unwind to caller

// Possibly throwing function call within a catch-all
void test5() {
  try {
    may_throw();
  } catch (...) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test5v()

// CHECK:   %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB]]] unwind to caller

// CHECK: [[CATCHSTART_BB]]:
// CHECK:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* null]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB0:.*]] unwind label %[[EHCLEANUP_BB:.*]]

// CHECK: [[INVOKE_CONT_BB0]]:
// CHECK-NEXT:   call void @@__cxa_end_catch() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:   catchret from %[[CATCHPAD]] to label

// CHECK: [[EHCLEANUP_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD0]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB1:.*]] unwind label %[[TERMINATE_BB:.*]]

// CHECK: [[INVOKE_CONT_BB1]]:
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind to caller

// CHECK: [[TERMINATE_BB]]:
// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CLEANUPPAD0]] []
// CHECK-NEXT:   %[[EXN:.*]] = call i8* @@llvm.wasm.get.exception(token %[[CLEANUPPAD1]])
// CHECK-NEXT:   call void @@__clang_call_terminate(i8* %[[EXN]]) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
// CHECK-NEXT:   unreachable

// CHECK-LABEL: define {{.*}} void @@__clang_call_terminate(i8*)
// CHECK-NEXT:   call i8* @@__cxa_begin_catch(i8* %{{.*}})
// CHECK-NEXT:   call void @@_ZSt9terminatev()
// CHECK-NEXT:   unreachable

// Try-catch with cleanups
void test6() {
  Cleanup c1;
  try {
    Cleanup c2;
    may_throw();
  } catch (int) {
    Cleanup c3;
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test6v()
// CHECK:   invoke void @@_Z9may_throwv()
// CHECK-NEXT:           to label %{{.*}} unwind label %[[EHCLEANUP_BB0:.*]]

// CHECK: [[EHCLEANUP_BB0]]:
// CHECK-NEXT:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* {{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD0]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD0]] unwind label %[[CATCH_DISPATCH_BB:.*]]

// CHECK: [[CATCH_DISPATCH_BB]]:
// CHECK-NEXT:  %[[CATCHSWITCH:.*]] = catchswitch within none [label %[[CATCHSTART_BB:.*]]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[CATCHSTART_BB]]:
// CHECK-NEXT:   %[[CATCHPAD:.*]] = catchpad within %[[CATCHSWITCH]] [i8* bitcast (i8** @@_ZTIi to i8*)]
// CHECK:   br i1 %{{.*}}, label %[[CATCH_INT_BB:.*]], label %[[RETHROW_BB:.*]]

// CHECK: [[CATCH_INT_BB]]:
// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:           to label %[[INVOKE_CONT_BB:.*]] unwind label %[[EHCLEANUP_BB2:.*]]

// CHECK: [[INVOKE_CONT_BB]]:
// CHECK:   catchret from %[[CATCHPAD]] to label %{{.*}}

// CHECK: [[RETHROW_BB]]:
// CHECK-NEXT:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD]]) ]
// CHECK-NEXT:          to label %[[UNREACHABLE_BB:.*]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[EHCLEANUP_BB2]]:
// CHECK-NEXT:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD2]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD2]] unwind label %[[EHCLEANUP_BB3:.*]]

// CHECK: [[EHCLEANUP_BB3]]:
// CHECK-NEXT:   %[[CLEANUPPAD3:.*]] = cleanuppad within %[[CATCHPAD]] []
// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label %[[EHCLEANUP_BB1:.*]]

// CHECK: [[EHCLEANUP_BB1]]:
// CHECK-NEXT:   %[[CLEANUPPAD1:.*]] = cleanuppad within none []
// CHECK-NEXT:   call %struct.Cleanup* @@_ZN7CleanupD1Ev(%struct.Cleanup* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD1]]) ]
// CHECK-NEXT:   cleanupret from %[[CLEANUPPAD1]] unwind to caller

// CHECK: [[UNREACHABLE_BB]]:
// CHECK-NEXT:   unreachable

// Nested try-catches within a try with cleanups
void test7() {
  Cleanup c1;
  may_throw();
  try {
    Cleanup c2;
    may_throw();
    try {
      Cleanup c3;
      may_throw();
    } catch (int) {
      may_throw();
    } catch (double) {
      may_throw();
    }
  } catch (int) {
    may_throw();
  } catch (...) {
    may_throw();
  }
}

// CHECK-LABEL: @@_Z5test7v()
// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label

// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* bitcast (i8** @@_ZTId to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind label

// CHECK:   %[[CLEANUPPAD2:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD2]] unwind label

// CHECK:   %[[CLEANUPPAD3:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD3]] unwind label

// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @@_ZTIi to i8*), i8* null]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   %[[CLEANUPPAD4:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   invoke void @@__cxa_end_catch() [ "funclet"(token %[[CLEANUPPAD4]]) ]

// CHECK:   cleanupret from %[[CLEANUPPAD4]] unwind label

// CHECK:   %[[CLEANUPPAD5:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   cleanupret from %[[CLEANUPPAD5]] unwind label

// CHECK:   %[[CLEANUPPAD6:.*]] = cleanuppad within none []
// CHECK:   cleanupret from %[[CLEANUPPAD6]] unwind to caller

// CHECK:   unreachable

// CHECK:   %[[CLEANUPPAD7:.*]] = cleanuppad within %[[CLEANUPPAD4]] []
// CHECK:   call void @@__clang_call_terminate(i8* %{{.*}}) {{.*}} [ "funclet"(token %[[CLEANUPPAD7]]) ]
// CHECK:   unreachable

// Nested try-catches within a catch
void test8() {
  try {
    may_throw();
  } catch (int) {
    try {
      may_throw();
    } catch (int) {
      may_throw();
    }
  }
}

// CHECK-LABEL: @@_Z5test8v()
// CHECK:   invoke void @@_Z9may_throwv()

// CHECK:   %[[CATCHSWITCH0:.*]] = catchswitch within none

// CHECK:   %[[CATCHPAD0:.*]] = catchpad within %[[CATCHSWITCH0]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD0]]) ]

// CHECK:   %[[CATCHSWITCH1:.*]] = catchswitch within %[[CATCHPAD0]]

// CHECK:   %[[CATCHPAD1:.*]] = catchpad within %[[CATCHSWITCH1]] [i8* bitcast (i8** @@_ZTIi to i8*)]

// CHECK:   invoke void @@_Z9may_throwv() [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD1]] to label

// CHECK:   invoke void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD1]]) ]

// CHECK:   catchret from %[[CATCHPAD0]] to label

// CHECK:   call void @@__cxa_rethrow() {{.*}} [ "funclet"(token %[[CATCHPAD0]]) ]
// CHECK:   unreachable

// CHECK:   %[[CLEANUPPAD0:.*]] = cleanuppad within %[[CATCHPAD1]] []
// CHECK:   cleanupret from %[[CLEANUPPAD0]] unwind label

// CHECK:   %[[CLEANUPPAD1:.*]] = cleanuppad within %[[CATCHPAD0]] []
// CHECK:   cleanupret from %[[CLEANUPPAD1]] unwind to caller

// CHECK:   unreachable
@


