2 The exception module defines all system-level exceptions and provides a
3 mechanism to alter system-level error handling.
5 Copyright: Copyright Sean Kelly 2005 - 2013.
6 License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
7 Authors: Sean Kelly and $(HTTP jmdavisprog.com, Jonathan M Davis)
8 Source: $(DRUNTIMESRC core/_exception.d)
10 module core
.exception
;
12 // Compiler lowers final switch default case to this (which is a runtime error)
13 void __switch_errorT()(string file
= __FILE__
, size_t line
= __LINE__
) @trusted
15 // Consider making this a compile time check.
16 version (D_Exceptions
)
17 throw staticError
!SwitchError("No appropriate switch clause found", file
, line
, null);
19 assert(0, "No appropriate switch clause found");
23 * Thrown on a range error.
25 class RangeError
: Error
27 this( string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @nogc nothrow pure @safe
29 super( "Range violation", file
, line
, next
);
32 protected this( string msg
, string file
, size_t line
, Throwable next
= null ) @nogc nothrow pure @safe
34 super( msg
, file
, line
, next
);
41 auto re
= new RangeError();
42 assert(re
.file
== __FILE__
);
43 assert(re
.line
== __LINE__
- 2);
44 assert(re
.next
is null);
45 assert(re
.msg
== "Range violation");
49 auto re
= new RangeError("hello", 42, new Exception("It's an Exception!"));
50 assert(re
.file
== "hello");
51 assert(re
.line
== 42);
52 assert(re
.next
!is null);
53 assert(re
.msg
== "Range violation");
58 * Thrown when an out of bounds array index is accessed.
60 class ArrayIndexError
: RangeError
64 /// Length of indexed array
67 // Buffer to avoid GC allocations
68 private immutable char[100] msgBuf
= '\0';
70 this(size_t index
, size_t length
, string file
= __FILE__
,
71 size_t line
= __LINE__
, Throwable next
= null) @nogc nothrow pure @safe
76 // Constructing the message is a bit clumsy:
77 // It's essentially `printf("index [%zu] is out of bounds for array of length [%zu]", index, length)`,
78 // but even `snprintf` isn't `pure`.
79 // Also string concatenation isn't `@nogc`, and casting to/from immutable isn't `@safe`
80 import core
.internal
.string
: unsignedToTempString
;
81 char[msgBuf
.length
] buf
= void;
82 char[20] tmpBuf
= void;
84 sink
.rangeMsgPut("index [");
85 sink
.rangeMsgPut(unsignedToTempString
!10(index
, tmpBuf
));
86 sink
.rangeMsgPut("] is out of bounds for array of length ");
87 sink
.rangeMsgPut(unsignedToTempString
!10(length
, tmpBuf
));
89 super(msgBuf
[0..$-sink
.length
], file
, line
, next
);
95 assert(new ArrayIndexError(900, 700).msg
== "index [900] is out of bounds for array of length 700");
96 // Ensure msg buffer doesn't overflow on large numbers
97 assert(new ArrayIndexError(size_t
.max
, size_t
.max
-1).msg
);
104 _d_arraybounds_indexp("test", 400, 9, 3);
105 assert(0, "no ArrayIndexError thrown");
107 catch (ArrayIndexError re
)
109 assert(re
.file
== "test");
110 assert(re
.line
== 400);
111 assert(re
.index
== 9);
112 assert(re
.length
== 3);
117 * Thrown when an out of bounds array slice is created
119 class ArraySliceError
: RangeError
121 /// Lower/upper bound passed to slice: `array[lower .. upper]`
122 const size_t lower
, upper
;
123 /// Length of sliced array
126 private immutable char[120] msgBuf
= '\0';
128 this(size_t lower
, size_t upper
, size_t length
, string file
= __FILE__
,
129 size_t line
= __LINE__
, Throwable next
= null) @nogc nothrow pure @safe
133 this.length
= length
;
135 // Constructing the message is a bit clumsy for the same reasons as ArrayIndexError
136 import core
.internal
.string
: unsignedToTempString
;
137 char[msgBuf
.length
] buf
= void;
138 char[20] tmpBuf
= void;
140 sink
.rangeMsgPut("slice [");
141 sink
.rangeMsgPut(unsignedToTempString
!10(lower
, tmpBuf
));
142 sink
.rangeMsgPut(" .. ");
143 sink
.rangeMsgPut(unsignedToTempString
!10(upper
, tmpBuf
));
144 sink
.rangeMsgPut("] ");
147 sink
.rangeMsgPut("has a larger lower index than upper index");
151 sink
.rangeMsgPut("extends past source array of length ");
152 sink
.rangeMsgPut(unsignedToTempString
!10(length
, tmpBuf
));
156 super(msgBuf
[0..$-sink
.length
], file
, line
, next
);
162 assert(new ArraySliceError(40, 80, 20).msg
== "slice [40 .. 80] extends past source array of length 20");
163 assert(new ArraySliceError(90, 70, 20).msg
== "slice [90 .. 70] has a larger lower index than upper index");
164 // Ensure msg buffer doesn't overflow on large numbers
165 assert(new ArraySliceError(size_t
.max
, size_t
.max
, size_t
.max
-1).msg
);
172 _d_arraybounds_slicep("test", 400, 1, 7, 3);
173 assert(0, "no ArraySliceError thrown");
175 catch (ArraySliceError re
)
177 assert(re
.file
== "test");
178 assert(re
.line
== 400);
179 assert(re
.lower
== 1);
180 assert(re
.upper
== 7);
181 assert(re
.length
== 3);
185 /// Mini `std.range.primitives: put` for constructor of ArraySliceError / ArrayIndexError
186 private void rangeMsgPut(ref char[] r
, scope const(char)[] e
) @nogc nothrow pure @safe
188 assert(r
.length
>= e
.length
); // don't throw ArraySliceError inside ArrayIndexError ctor
189 r
[0 .. e
.length
] = e
[];
190 r
= r
[e
.length
.. $];
194 * Thrown on an assert error.
196 class AssertError
: Error
198 @safe pure nothrow @nogc this( string file
, size_t line
)
200 this(cast(Throwable
)null, file
, line
);
203 @safe pure nothrow @nogc this( Throwable next
, string file
= __FILE__
, size_t line
= __LINE__
)
205 this( "Assertion failure", file
, line
, next
);
208 @safe pure nothrow @nogc this( string msg
, string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null )
210 super( msg
, file
, line
, next
);
217 auto ae
= new AssertError("hello", 42);
218 assert(ae
.file
== "hello");
219 assert(ae
.line
== 42);
220 assert(ae
.next
is null);
221 assert(ae
.msg
== "Assertion failure");
225 auto ae
= new AssertError(new Exception("It's an Exception!"));
226 assert(ae
.file
== __FILE__
);
227 assert(ae
.line
== __LINE__
- 2);
228 assert(ae
.next
!is null);
229 assert(ae
.msg
== "Assertion failure");
233 auto ae
= new AssertError(new Exception("It's an Exception!"), "hello", 42);
234 assert(ae
.file
== "hello");
235 assert(ae
.line
== 42);
236 assert(ae
.next
!is null);
237 assert(ae
.msg
== "Assertion failure");
241 auto ae
= new AssertError("msg");
242 assert(ae
.file
== __FILE__
);
243 assert(ae
.line
== __LINE__
- 2);
244 assert(ae
.next
is null);
245 assert(ae
.msg
== "msg");
249 auto ae
= new AssertError("msg", "hello", 42);
250 assert(ae
.file
== "hello");
251 assert(ae
.line
== 42);
252 assert(ae
.next
is null);
253 assert(ae
.msg
== "msg");
257 auto ae
= new AssertError("msg", "hello", 42, new Exception("It's an Exception!"));
258 assert(ae
.file
== "hello");
259 assert(ae
.line
== 42);
260 assert(ae
.next
!is null);
261 assert(ae
.msg
== "msg");
267 * Thrown on finalize error.
269 class FinalizeError
: Error
273 this( TypeInfo ci
, Throwable next
, string file
= __FILE__
, size_t line
= __LINE__
) @safe pure nothrow @nogc
275 this(ci
, file
, line
, next
);
278 this( TypeInfo ci
, string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @safe pure nothrow @nogc
280 super( "Finalization error", file
, line
, next
);
284 override string
toString() const @safe
286 return "An exception was thrown while finalizing an instance of " ~ info
.toString();
292 ClassInfo info
= new ClassInfo
;
293 info
.name
= "testInfo";
296 auto fe
= new FinalizeError(info
);
297 assert(fe
.file
== __FILE__
);
298 assert(fe
.line
== __LINE__
- 2);
299 assert(fe
.next
is null);
300 assert(fe
.msg
== "Finalization error");
301 assert(fe
.info
== info
);
305 auto fe
= new FinalizeError(info
, new Exception("It's an Exception!"));
306 assert(fe
.file
== __FILE__
);
307 assert(fe
.line
== __LINE__
- 2);
308 assert(fe
.next
!is null);
309 assert(fe
.msg
== "Finalization error");
310 assert(fe
.info
== info
);
314 auto fe
= new FinalizeError(info
, "hello", 42);
315 assert(fe
.file
== "hello");
316 assert(fe
.line
== 42);
317 assert(fe
.next
is null);
318 assert(fe
.msg
== "Finalization error");
319 assert(fe
.info
== info
);
323 auto fe
= new FinalizeError(info
, "hello", 42, new Exception("It's an Exception!"));
324 assert(fe
.file
== "hello");
325 assert(fe
.line
== 42);
326 assert(fe
.next
!is null);
327 assert(fe
.msg
== "Finalization error");
328 assert(fe
.info
== info
);
333 * Thrown on an out of memory error.
335 class OutOfMemoryError
: Error
337 this(string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @safe pure nothrow @nogc
339 this(true, file
, line
, next
);
342 this(bool trace
, string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @safe pure nothrow @nogc
344 super("Memory allocation failed", file
, line
, next
);
346 this.info
= SuppressTraceInfo
.instance
;
349 override string
toString() const @trusted
351 return msg
.length ?
(cast()this).superToString() : "Memory allocation failed";
354 // kludge to call non-const super.toString
355 private string
superToString() @trusted
357 return super.toString();
364 auto oome
= new OutOfMemoryError();
365 assert(oome
.file
== __FILE__
);
366 assert(oome
.line
== __LINE__
- 2);
367 assert(oome
.next
is null);
368 assert(oome
.msg
== "Memory allocation failed");
369 assert(oome
.toString
.length
);
373 auto oome
= new OutOfMemoryError("hello", 42, new Exception("It's an Exception!"));
374 assert(oome
.file
== "hello");
375 assert(oome
.line
== 42);
376 assert(oome
.next
!is null);
377 assert(oome
.msg
== "Memory allocation failed");
383 * Thrown on an invalid memory operation.
385 * An invalid memory operation error occurs in circumstances when the garbage
386 * collector has detected an operation it cannot reliably handle. The default
387 * D GC is not re-entrant, so this can happen due to allocations done from
388 * within finalizers called during a garbage collection cycle.
390 class InvalidMemoryOperationError
: Error
392 this(string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @safe pure nothrow @nogc
394 super( "Invalid memory operation", file
, line
, next
);
397 override string
toString() const @trusted
399 return msg
.length ?
(cast()this).superToString() : "Invalid memory operation";
402 // kludge to call non-const super.toString
403 private string
superToString() @trusted
405 return super.toString();
412 auto oome
= new InvalidMemoryOperationError();
413 assert(oome
.file
== __FILE__
);
414 assert(oome
.line
== __LINE__
- 2);
415 assert(oome
.next
is null);
416 assert(oome
.msg
== "Invalid memory operation");
417 assert(oome
.toString
.length
);
421 auto oome
= new InvalidMemoryOperationError("hello", 42, new Exception("It's an Exception!"));
422 assert(oome
.file
== "hello");
423 assert(oome
.line
== 42);
424 assert(oome
.next
!is null);
425 assert(oome
.msg
== "Invalid memory operation");
431 * Thrown on a configuration error.
433 class ForkError
: Error
435 this( string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @nogc nothrow pure @safe
437 super( "fork() failed", file
, line
, next
);
443 * Thrown on a switch error.
445 class SwitchError
: Error
447 @safe pure nothrow @nogc this( string msg
, string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null )
449 super( msg
, file
, line
, next
);
456 auto se
= new SwitchError("No appropriate switch clause found");
457 assert(se
.file
== __FILE__
);
458 assert(se
.line
== __LINE__
- 2);
459 assert(se
.next
is null);
460 assert(se
.msg
== "No appropriate switch clause found");
464 auto se
= new SwitchError("No appropriate switch clause found", "hello", 42, new Exception("It's an Exception!"));
465 assert(se
.file
== "hello");
466 assert(se
.line
== 42);
467 assert(se
.next
!is null);
468 assert(se
.msg
== "No appropriate switch clause found");
474 * Thrown on a unicode conversion error.
476 class UnicodeException
: Exception
480 this( string msg
, size_t idx
, string file
= __FILE__
, size_t line
= __LINE__
, Throwable next
= null ) @safe pure nothrow @nogc
482 super( msg
, file
, line
, next
);
490 auto ue
= new UnicodeException("msg", 2);
491 assert(ue
.file
== __FILE__
);
492 assert(ue
.line
== __LINE__
- 2);
493 assert(ue
.next
is null);
494 assert(ue
.msg
== "msg");
499 auto ue
= new UnicodeException("msg", 2, "hello", 42, new Exception("It's an Exception!"));
500 assert(ue
.file
== "hello");
501 assert(ue
.line
== 42);
502 assert(ue
.next
!is null);
503 assert(ue
.msg
== "msg");
509 ///////////////////////////////////////////////////////////////////////////////
511 ///////////////////////////////////////////////////////////////////////////////
514 // NOTE: One assert handler is used for all threads. Thread-local
515 // behavior should occur within the handler itself. This delegate
516 // is __gshared for now based on the assumption that it will only
517 // set by the main thread during program initialization.
518 private __gshared AssertHandler _assertHandler
= null;
522 Gets/sets assert hander. null means the default handler is used.
524 alias AssertHandler
= void function(string file
, size_t line
, string msg
) nothrow;
527 @property AssertHandler
assertHandler() @trusted nothrow @nogc
529 return _assertHandler
;
533 @property void assertHandler(AssertHandler handler
) @trusted nothrow @nogc
535 _assertHandler
= handler
;
539 ///////////////////////////////////////////////////////////////////////////////
540 // Overridable Callbacks
541 ///////////////////////////////////////////////////////////////////////////////
545 * A callback for assert errors in D. The user-supplied assert handler will
546 * be called if one has been supplied, otherwise an $(LREF AssertError) will be
550 * file = The name of the file that signaled this error.
551 * line = The line number on which this error occurred.
553 extern (C
) void onAssertError( string file
= __FILE__
, size_t line
= __LINE__
) nothrow
555 if ( _assertHandler
is null )
556 throw staticError
!AssertError(file
, line
);
557 _assertHandler( file
, line
, null);
562 * A callback for assert errors in D. The user-supplied assert handler will
563 * be called if one has been supplied, otherwise an $(LREF AssertError) will be
567 * file = The name of the file that signaled this error.
568 * line = The line number on which this error occurred.
569 * msg = An error message supplied by the user.
571 extern (C
) void onAssertErrorMsg( string file
, size_t line
, string msg
) nothrow
573 if ( _assertHandler
is null )
574 throw staticError
!AssertError(msg
, file
, line
);
575 _assertHandler( file
, line
, msg
);
580 * A callback for unittest errors in D. The user-supplied unittest handler
581 * will be called if one has been supplied, otherwise the error will be
585 * file = The name of the file that signaled this error.
586 * line = The line number on which this error occurred.
587 * msg = An error message supplied by the user.
589 extern (C
) void onUnittestErrorMsg( string file
, size_t line
, string msg
) nothrow
591 onAssertErrorMsg( file
, line
, msg
);
595 ///////////////////////////////////////////////////////////////////////////////
596 // Internal Error Callbacks
597 ///////////////////////////////////////////////////////////////////////////////
600 * A callback for general array bounds errors in D. A $(LREF RangeError) will be thrown.
603 * file = The name of the file that signaled this error.
604 * line = The line number on which this error occurred.
607 * $(LREF RangeError).
609 extern (C
) noreturn
onRangeError( string file
= __FILE__
, size_t line
= __LINE__
) @trusted pure nothrow @nogc
611 throw staticError
!RangeError(file
, line
, null);
615 * A callback for array slice out of bounds errors in D.
618 * lower = the lower bound of the index passed of a slice
619 * upper = the upper bound of the index passed of a slice or the index if not a slice
620 * length = length of the array
621 * file = The name of the file that signaled this error.
622 * line = The line number on which this error occurred.
625 * $(LREF ArraySliceError).
627 extern (C
) noreturn
onArraySliceError( size_t lower
= 0, size_t upper
= 0, size_t length
= 0,
628 string file
= __FILE__
, size_t line
= __LINE__
) @trusted pure nothrow @nogc
630 throw staticError
!ArraySliceError(lower
, upper
, length
, file
, line
, null);
634 * A callback for array index out of bounds errors in D.
637 * index = index in the array
638 * length = length of the array
639 * file = The name of the file that signaled this error.
640 * line = The line number on which this error occurred.
643 * $(LREF ArrayIndexError).
645 extern (C
) noreturn
onArrayIndexError( size_t index
= 0, size_t length
= 0,
646 string file
= __FILE__
, size_t line
= __LINE__
) @trusted pure nothrow @nogc
648 throw staticError
!ArrayIndexError(index
, length
, file
, line
, null);
652 * A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown.
655 * info = The TypeInfo instance for the object that failed finalization.
656 * e = The exception thrown during finalization.
657 * file = The name of the file that signaled this error.
658 * line = The line number on which this error occurred.
661 * $(LREF FinalizeError).
663 extern (C
) noreturn
onFinalizeError( TypeInfo info
, Throwable e
, string file
= __FILE__
, size_t line
= __LINE__
) @trusted nothrow
665 // This error is thrown during a garbage collection, so no allocation must occur while
666 // generating this object. So we use a preallocated instance
667 throw staticError
!FinalizeError(info
, e
, file
, line
);
672 // When compiling with -betterC we use template functions so if they are
673 // used the bodies are copied into the user's program so there is no need
674 // for the D runtime during linking.
676 // In the future we might want to convert all functions in this module to
677 // templates even for ordinary builds instead of providing them as an
678 // extern(C) library.
680 noreturn
onOutOfMemoryError()(void* pretend_sideffect
= null) @nogc nothrow pure @trusted
682 assert(0, "Memory allocation failed");
684 alias onOutOfMemoryErrorNoGC
= onOutOfMemoryError
;
686 noreturn
onInvalidMemoryOperationError()(void* pretend_sideffect
= null) @nogc nothrow pure @trusted
688 assert(0, "Invalid memory operation");
694 * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be
698 * $(LREF OutOfMemoryError).
700 extern (C
) noreturn
onOutOfMemoryError(void* pretend_sideffect
= null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
702 // NOTE: Since an out of memory condition exists, no allocation must occur
703 // while generating this object.
704 throw staticError
!OutOfMemoryError();
707 extern (C
) noreturn
onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
709 // suppress stacktrace until they are @nogc
710 throw staticError
!OutOfMemoryError(false);
715 * A callback for invalid memory operations in D. An
716 * $(LREF InvalidMemoryOperationError) will be thrown.
719 * $(LREF InvalidMemoryOperationError).
721 extern (C
) noreturn
onInvalidMemoryOperationError(void* pretend_sideffect
= null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
723 // The same restriction applies as for onOutOfMemoryError. The GC is in an
724 // undefined state, thus no allocation must occur while generating this object.
725 throw staticError
!InvalidMemoryOperationError();
730 * A callback for errors in the case of a failed fork in D. A $(LREF ForkError) will be thrown.
733 * file = The name of the file that signaled this error.
734 * line = The line number on which this error occurred.
737 * $(LREF ConfigurationError).
739 extern (C
) noreturn
onForkError( string file
= __FILE__
, size_t line
= __LINE__
) @trusted pure nothrow @nogc
741 throw staticError
!ForkError( file
, line
, null );
745 * A callback for unicode errors in D. A $(LREF UnicodeException) will be thrown.
748 * msg = Information about the error.
749 * idx = String index where this error was detected.
750 * file = The name of the file that signaled this error.
751 * line = The line number on which this error occurred.
754 * $(LREF UnicodeException).
756 extern (C
) noreturn
onUnicodeError( string msg
, size_t idx
, string file
= __FILE__
, size_t line
= __LINE__
) @safe pure
758 throw new UnicodeException( msg
, idx
, file
, line
);
761 /***********************************
762 * These functions must be defined for any D program linked
763 * against this library.
766 extern (C) void onAssertError(string file, size_t line);
767 extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
768 extern (C) void onUnittestErrorMsg(string file, size_t line, string msg);
769 extern (C) void onRangeError(string file, size_t line);
770 extern (C) void onHiddenFuncError(Object o);
773 /***********************************
774 * Function calls to these are generated by the compiler and inserted into
780 /* One of these three is called upon an assert() fail.
782 void _d_assertp(immutable(char)* file
, uint line
)
784 import core
.stdc
.string
: strlen
;
785 onAssertError(file
[0 .. strlen(file
)], line
);
788 void _d_assert_msg(string msg
, string file
, uint line
)
790 onAssertErrorMsg(file
, line
, msg
);
793 void _d_assert(string file
, uint line
)
795 onAssertError(file
, line
);
798 /* One of these three is called upon an assert() fail inside of a unittest block
800 void _d_unittestp(immutable(char)* file
, uint line
)
802 import core
.stdc
.string
: strlen
;
803 _d_unittest(file
[0 .. strlen(file
)], line
);
806 void _d_unittest_msg(string msg
, string file
, uint line
)
808 onUnittestErrorMsg(file
, line
, msg
);
811 void _d_unittest(string file
, uint line
)
813 _d_unittest_msg("unittest failure", file
, line
);
816 /// Called when an invalid array index/slice or associative array key is accessed
817 void _d_arrayboundsp(immutable(char*) file
, uint line
)
819 import core
.stdc
.string
: strlen
;
820 onRangeError(file
[0 .. strlen(file
)], line
);
824 void _d_arraybounds(string file
, uint line
)
826 onRangeError(file
, line
);
829 /// Called when an out of range slice of an array is created
830 void _d_arraybounds_slicep(immutable(char*) file
, uint line
, size_t lower
, size_t upper
, size_t length
)
832 import core
.stdc
.string
: strlen
;
833 onArraySliceError(lower
, upper
, length
, file
[0 .. strlen(file
)], line
);
837 void _d_arraybounds_slice(string file
, uint line
, size_t lower
, size_t upper
, size_t length
)
839 onArraySliceError(lower
, upper
, length
, file
, line
);
842 /// Called when an out of range array index is accessed
843 void _d_arraybounds_indexp(immutable(char*) file
, uint line
, size_t index
, size_t length
)
845 import core
.stdc
.string
: strlen
;
846 onArrayIndexError(index
, length
, file
[0 .. strlen(file
)], line
);
850 void _d_arraybounds_index(string file
, uint line
, size_t index
, size_t length
)
852 onArrayIndexError(index
, length
, file
, line
);
856 // TLS storage shared for all errors, chaining might create circular reference
857 private align(2 * size_t
.sizeof
) void[256] _store
;
859 // only Errors for now as those are rarely chained
860 package T
staticError(T
, Args
...)(auto ref Args args
)
863 // pure hack, what we actually need is @noreturn and allow to call that in pure functions
866 static assert(__traits(classInstanceSize
, T
) <= _store
.length
,
867 T
.stringof
~ " is too large for staticError()");
869 return cast(T
) _store
.ptr
;
871 auto res
= (cast(T
function() @trusted pure nothrow @nogc) &get
)();
872 import core
.lifetime
: emplace
;
877 // Suppress traceinfo generation when the GC cannot be used. Workaround for
878 // Bugzilla 14993. We should make stack traces @nogc instead.
879 package class SuppressTraceInfo
: Throwable
.TraceInfo
881 override int opApply(scope int delegate(ref const(char[]))) const { return 0; }
882 override int opApply(scope int delegate(ref size_t
, ref const(char[]))) const { return 0; }
883 override string
toString() const { return null; }
884 static SuppressTraceInfo
instance() @trusted @nogc pure nothrow
886 static immutable SuppressTraceInfo it
= new SuppressTraceInfo
;
887 return cast(SuppressTraceInfo
)it
;