d: Merge upstream dmd, druntime 26f049fb26, phobos 330d6a4fd.
[official-gcc.git] / libphobos / libdruntime / core / exception.d
blobd2016b115f113af22605ada3a5068f06767a4f05
1 /**
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)
9 */
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);
18 else
19 assert(0, "No appropriate switch clause found");
22 /**
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 );
38 unittest
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");
57 /**
58 * Thrown when an out of bounds array index is accessed.
60 class ArrayIndexError : RangeError
62 /// Index into array
63 const size_t index;
64 /// Length of indexed array
65 const size_t length;
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
73 this.index = index;
74 this.length = length;
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;
83 char[] sink = buf[];
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));
88 this.msgBuf = buf;
89 super(msgBuf[0..$-sink.length], file, line, next);
93 @safe pure unittest
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);
100 unittest
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
124 const size_t length;
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
131 this.lower = lower;
132 this.upper = upper;
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;
139 char[] sink = buf;
140 sink.rangeMsgPut("slice [");
141 sink.rangeMsgPut(unsignedToTempString!10(lower, tmpBuf));
142 sink.rangeMsgPut(" .. ");
143 sink.rangeMsgPut(unsignedToTempString!10(upper, tmpBuf));
144 sink.rangeMsgPut("] ");
145 if (lower > upper)
147 sink.rangeMsgPut("has a larger lower index than upper index");
149 else
151 sink.rangeMsgPut("extends past source array of length ");
152 sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
155 this.msgBuf = buf;
156 super(msgBuf[0..$-sink.length], file, line, next);
160 @safe pure unittest
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);
168 unittest
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 );
214 unittest
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
271 TypeInfo info;
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 );
281 info = ci;
284 override string toString() const @safe
286 return "An exception was thrown while finalizing an instance of " ~ info.toString();
290 unittest
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);
345 if (!trace)
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();
361 unittest
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();
409 unittest
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 );
453 unittest
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
478 size_t idx;
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 );
483 this.idx = idx;
487 unittest
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");
495 assert(ue.idx == 2);
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");
504 assert(ue.idx == 2);
509 ///////////////////////////////////////////////////////////////////////////////
510 // Overrides
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;
526 /// ditto
527 @property AssertHandler assertHandler() @trusted nothrow @nogc
529 return _assertHandler;
532 /// ditto
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
547 * thrown.
549 * Params:
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
564 * thrown.
566 * Params:
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
582 * written to stderr.
584 * Params:
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.
602 * Params:
603 * file = The name of the file that signaled this error.
604 * line = The line number on which this error occurred.
606 * Throws:
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.
617 * Params:
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.
624 * Throws:
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.
636 * Params:
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.
642 * Throws:
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.
654 * Params:
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.
660 * Throws:
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);
670 version (D_BetterC)
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");
691 else
694 * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be
695 * thrown.
697 * Throws:
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.
718 * Throws:
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.
732 * Params:
733 * file = The name of the file that signaled this error.
734 * line = The line number on which this error occurred.
736 * Throws:
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.
747 * Params:
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.
753 * Throws:
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
775 * the object code.
778 extern (C)
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);
823 /// ditto
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);
836 /// ditto
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);
849 /// ditto
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)
861 if (is(T : Error))
863 // pure hack, what we actually need is @noreturn and allow to call that in pure functions
864 static T get()
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;
873 emplace(res, args);
874 return res;
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;