1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: no-exceptions 10 11 #include <assert.h> 12 #include <stddef.h> 13 #include <unwind.h> 14 15 extern "C" _Unwind_Reason_Code 16 trace_function(struct _Unwind_Context*, void* ntraced) { 17 (*reinterpret_cast<size_t*>(ntraced))++; 18 // We should never have a call stack this deep... 19 assert(*reinterpret_cast<size_t*>(ntraced) < 20); 20 return _URC_NO_REASON; 21 } 22 23 __attribute__ ((__noinline__)) 24 void call3_throw(size_t* ntraced) { 25 try { 26 _Unwind_Backtrace(trace_function, ntraced); 27 } catch (...) { 28 assert(false); 29 } 30 } 31 32 __attribute__ ((__noinline__, __disable_tail_calls__)) 33 void call3_nothrow(size_t* ntraced) { 34 _Unwind_Backtrace(trace_function, ntraced); 35 } 36 37 __attribute__ ((__noinline__, __disable_tail_calls__)) 38 void call2(size_t* ntraced, bool do_throw) { 39 if (do_throw) { 40 call3_throw(ntraced); 41 } else { 42 call3_nothrow(ntraced); 43 } 44 } 45 46 __attribute__ ((__noinline__, __disable_tail_calls__)) 47 void call1(size_t* ntraced, bool do_throw) { 48 call2(ntraced, do_throw); 49 } 50 51 int main(int, char**) { 52 size_t throw_ntraced = 0; 53 size_t nothrow_ntraced = 0; 54 55 call1(¬hrow_ntraced, false); 56 57 try { 58 call1(&throw_ntraced, true); 59 } catch (...) { 60 assert(false); 61 } 62 63 // Different platforms (and different runtimes) will unwind a different number 64 // of times, so we can't make any better assumptions than this. 65 assert(nothrow_ntraced > 1); 66 assert(throw_ntraced == nothrow_ntraced); // Make sure we unwind through catch 67 return 0; 68 } 69