xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/libdruntime/core/exception.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /**
2     The exception module defines all system-level exceptions and provides a
3     mechanism to alter system-level error handling.
4 
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;
11 
12 // Compiler lowers final switch default case to this (which is a runtime error)
__switch_errorT()13 void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
14 {
15     // Consider making this a compile time check.
16     version (D_Exceptions)
17         throw staticError!SwitchError(file, line, null);
18     else
19         assert(0, "No appropriate switch clause found");
20 }
21 
22 /**
23  * Thrown on a range error.
24  */
25 class RangeError : Error
26 {
27     this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
28     {
29         super( "Range violation", file, line, next );
30     }
31 
32     protected this( string msg, string file, size_t line, Throwable next = null ) @nogc nothrow pure @safe
33     {
34         super( msg, file, line, next );
35     }
36 }
37 
38 unittest
39 {
40     {
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");
46     }
47 
48     {
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");
54     }
55 }
56 
57 /**
58  * Thrown when an out of bounds array index is accessed.
59  */
60 class ArrayIndexError : RangeError
61 {
62     /// Index into array
63     const size_t index;
64     /// Length of indexed array
65     const size_t length;
66 
67     // Buffer to avoid GC allocations
68     private immutable char[100] msgBuf = '\0';
69 
70     this(size_t index, size_t length, string file = __FILE__,
71          size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
72     {
73         this.index  = index;
74         this.length = length;
75 
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);
90     }
91 }
92 
93 @safe pure unittest
94 {
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);
98 }
99 
100 unittest
101 {
102     try
103     {
104         _d_arraybounds_indexp("test", 400, 9, 3);
105         assert(0, "no ArrayIndexError thrown");
106     }
catch(ArrayIndexError re)107     catch (ArrayIndexError re)
108     {
109         assert(re.file   == "test");
110         assert(re.line   == 400);
111         assert(re.index  == 9);
112         assert(re.length == 3);
113     }
114 }
115 
116 /**
117  * Thrown when an out of bounds array slice is created
118  */
119 class ArraySliceError : RangeError
120 {
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;
125 
126     private immutable char[120] msgBuf = '\0';
127 
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
130     {
131         this.lower  = lower;
132         this.upper  = upper;
133         this.length = length;
134 
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)
146         {
147             sink.rangeMsgPut("has a larger lower index than upper index");
148         }
149         else
150         {
151             sink.rangeMsgPut("extends past source array of length ");
152             sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
153         }
154 
155         this.msgBuf = buf;
156         super(msgBuf[0..$-sink.length], file, line, next);
157     }
158 }
159 
160 @safe pure unittest
161 {
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);
166 }
167 
168 unittest
169 {
170     try
171     {
172         _d_arraybounds_slicep("test", 400, 1, 7, 3);
173         assert(0, "no ArraySliceError thrown");
174     }
catch(ArraySliceError re)175     catch (ArraySliceError re)
176     {
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);
182     }
183 }
184 
185 /// Mini `std.range.primitives: put` for constructor of ArraySliceError / ArrayIndexError
rangeMsgPut(ref char[]r,scope const (char)[]e)186 private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure @safe
187 {
188     assert(r.length >= e.length); // don't throw ArraySliceError inside ArrayIndexError ctor
189     r[0 .. e.length] = e[];
190     r = r[e.length .. $];
191 }
192 
193 /**
194  * Thrown on an assert error.
195  */
196 class AssertError : Error
197 {
this(string file,size_t line)198     @safe pure nothrow @nogc this( string file, size_t line )
199     {
200         this(cast(Throwable)null, file, line);
201     }
202 
203     @safe pure nothrow @nogc this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
204     {
205         this( "Assertion failure", file, line, next);
206     }
207 
208     @safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
209     {
210         super( msg, file, line, next );
211     }
212 }
213 
214 unittest
215 {
216     {
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");
222     }
223 
224     {
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");
230     }
231 
232     {
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");
238     }
239 
240     {
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");
246     }
247 
248     {
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");
254     }
255 
256     {
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");
262     }
263 }
264 
265 
266 /**
267  * Thrown on finalize error.
268  */
269 class FinalizeError : Error
270 {
271     TypeInfo   info;
272 
273     this( TypeInfo ci, Throwable next, string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow @nogc
274     {
275         this(ci, file, line, next);
276     }
277 
278     this( TypeInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
279     {
280         super( "Finalization error", file, line, next );
281         super.info = SuppressTraceInfo.instance;
282         info = ci;
283     }
284 
toString()285     override string toString() const @safe
286     {
287         return "An exception was thrown while finalizing an instance of " ~ info.toString();
288     }
289 }
290 
291 unittest
292 {
293     ClassInfo info = new ClassInfo;
294     info.name = "testInfo";
295 
296     {
297         auto fe = new FinalizeError(info);
298         assert(fe.file == __FILE__);
299         assert(fe.line == __LINE__ - 2);
300         assert(fe.next is null);
301         assert(fe.msg == "Finalization error");
302         assert(fe.info == info);
303     }
304 
305     {
306         auto fe = new FinalizeError(info, new Exception("It's an Exception!"));
307         assert(fe.file == __FILE__);
308         assert(fe.line == __LINE__ - 2);
309         assert(fe.next !is null);
310         assert(fe.msg == "Finalization error");
311         assert(fe.info == info);
312     }
313 
314     {
315         auto fe = new FinalizeError(info, "hello", 42);
316         assert(fe.file == "hello");
317         assert(fe.line == 42);
318         assert(fe.next is null);
319         assert(fe.msg == "Finalization error");
320         assert(fe.info == info);
321     }
322 
323     {
324         auto fe = new FinalizeError(info, "hello", 42, new Exception("It's an Exception!"));
325         assert(fe.file == "hello");
326         assert(fe.line == 42);
327         assert(fe.next !is null);
328         assert(fe.msg == "Finalization error");
329         assert(fe.info == info);
330     }
331 }
332 
333 /**
334  * Thrown on an out of memory error.
335  */
336 class OutOfMemoryError : Error
337 {
338     this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
339     {
340         this(true, file, line, next);
341     }
342 
343     this(bool trace, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
344     {
345         super("Memory allocation failed", file, line, next);
346         if (!trace)
347             this.info = SuppressTraceInfo.instance;
348     }
349 
toString()350     override string toString() const @trusted
351     {
352         return msg.length ? (cast()this).superToString() : "Memory allocation failed";
353     }
354 
355     // kludge to call non-const super.toString
superToString()356     private string superToString() @trusted
357     {
358         return super.toString();
359     }
360 }
361 
362 unittest
363 {
364     {
365         auto oome = new OutOfMemoryError();
366         assert(oome.file == __FILE__);
367         assert(oome.line == __LINE__ - 2);
368         assert(oome.next is null);
369         assert(oome.msg == "Memory allocation failed");
370         assert(oome.toString.length);
371     }
372 
373     {
374         auto oome = new OutOfMemoryError("hello", 42, new Exception("It's an Exception!"));
375         assert(oome.file == "hello");
376         assert(oome.line == 42);
377         assert(oome.next !is null);
378         assert(oome.msg == "Memory allocation failed");
379     }
380 }
381 
382 
383 /**
384  * Thrown on an invalid memory operation.
385  *
386  * An invalid memory operation error occurs in circumstances when the garbage
387  * collector has detected an operation it cannot reliably handle. The default
388  * D GC is not re-entrant, so this can happen due to allocations done from
389  * within finalizers called during a garbage collection cycle.
390  */
391 class InvalidMemoryOperationError : Error
392 {
393     this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
394     {
395         super( "Invalid memory operation", file, line, next );
396         this.info = SuppressTraceInfo.instance;
397     }
398 
toString()399     override string toString() const @trusted
400     {
401         return msg.length ? (cast()this).superToString() : "Invalid memory operation";
402     }
403 
404     // kludge to call non-const super.toString
superToString()405     private string superToString() @trusted
406     {
407         return super.toString();
408     }
409 }
410 
411 unittest
412 {
413     {
414         auto oome = new InvalidMemoryOperationError();
415         assert(oome.file == __FILE__);
416         assert(oome.line == __LINE__ - 2);
417         assert(oome.next is null);
418         assert(oome.msg == "Invalid memory operation");
419         assert(oome.toString.length);
420     }
421 
422     {
423         auto oome = new InvalidMemoryOperationError("hello", 42, new Exception("It's an Exception!"));
424         assert(oome.file == "hello");
425         assert(oome.line == 42);
426         assert(oome.next !is null);
427         assert(oome.msg == "Invalid memory operation");
428     }
429 }
430 
431 
432 /**
433 * Thrown on a configuration error.
434 */
435 class ForkError : Error
436 {
437     this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
438     {
439         super( "fork() failed", file, line, next );
440     }
441 }
442 
443 
444 /**
445  * Thrown on a switch error.
446  */
447 class SwitchError : Error
448 {
449     @safe pure nothrow @nogc this( string file = __FILE__, size_t line = __LINE__, Throwable next = null )
450     {
451         super( "No appropriate switch clause found", file, line, next );
452     }
453 }
454 
455 unittest
456 {
457     {
458         auto se = new SwitchError();
459         assert(se.file == __FILE__);
460         assert(se.line == __LINE__ - 2);
461         assert(se.next is null);
462         assert(se.msg == "No appropriate switch clause found");
463     }
464 
465     {
466         auto se = new SwitchError("hello", 42, new Exception("It's an Exception!"));
467         assert(se.file == "hello");
468         assert(se.line == 42);
469         assert(se.next !is null);
470         assert(se.msg == "No appropriate switch clause found");
471     }
472 }
473 
474 
475 /**
476  * Thrown on a unicode conversion error.
477  */
478 class UnicodeException : Exception
479 {
480     size_t idx;
481 
482     this( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
483     {
484         super( msg, file, line, next );
485         this.idx = idx;
486     }
487 }
488 
489 unittest
490 {
491     {
492         auto ue = new UnicodeException("msg", 2);
493         assert(ue.file == __FILE__);
494         assert(ue.line == __LINE__ - 2);
495         assert(ue.next is null);
496         assert(ue.msg == "msg");
497         assert(ue.idx == 2);
498     }
499 
500     {
501         auto ue = new UnicodeException("msg", 2, "hello", 42, new Exception("It's an Exception!"));
502         assert(ue.file == "hello");
503         assert(ue.line == 42);
504         assert(ue.next !is null);
505         assert(ue.msg == "msg");
506         assert(ue.idx == 2);
507     }
508 }
509 
510 
511 ///////////////////////////////////////////////////////////////////////////////
512 // Overrides
513 ///////////////////////////////////////////////////////////////////////////////
514 
515 
516 // NOTE: One assert handler is used for all threads.  Thread-local
517 //       behavior should occur within the handler itself.  This delegate
518 //       is __gshared for now based on the assumption that it will only
519 //       set by the main thread during program initialization.
520 private __gshared AssertHandler _assertHandler = null;
521 
522 
523 /**
524 Gets/sets assert hander. null means the default handler is used.
525 */
526 alias AssertHandler = void function(string file, size_t line, string msg) nothrow;
527 
528 /// ditto
assertHandler()529 @property AssertHandler assertHandler() @trusted nothrow @nogc
530 {
531     return _assertHandler;
532 }
533 
534 /// ditto
assertHandler(AssertHandler handler)535 @property void assertHandler(AssertHandler handler) @trusted nothrow @nogc
536 {
537     _assertHandler = handler;
538 }
539 
540 
541 ///////////////////////////////////////////////////////////////////////////////
542 // Overridable Callbacks
543 ///////////////////////////////////////////////////////////////////////////////
544 
545 
546 /**
547  * A callback for assert errors in D.  The user-supplied assert handler will
548  * be called if one has been supplied, otherwise an $(LREF AssertError) will be
549  * thrown.
550  *
551  * Params:
552  *  file = The name of the file that signaled this error.
553  *  line = The line number on which this error occurred.
554  */
555 extern (C) void onAssertError( string file = __FILE__, size_t line = __LINE__ ) nothrow
556 {
557     if ( _assertHandler is null )
558         throw staticError!AssertError(file, line);
559     _assertHandler( file, line, null);
560 }
561 
562 
563 /**
564  * A callback for assert errors in D.  The user-supplied assert handler will
565  * be called if one has been supplied, otherwise an $(LREF AssertError) will be
566  * thrown.
567  *
568  * Params:
569  *  file = The name of the file that signaled this error.
570  *  line = The line number on which this error occurred.
571  *  msg  = An error message supplied by the user.
572  */
onAssertErrorMsg(string file,size_t line,string msg)573 extern (C) void onAssertErrorMsg( string file, size_t line, string msg ) nothrow
574 {
575     if ( _assertHandler is null )
576         throw staticError!AssertError(msg, file, line);
577     _assertHandler( file, line, msg );
578 }
579 
580 
581 /**
582  * A callback for unittest errors in D.  The user-supplied unittest handler
583  * will be called if one has been supplied, otherwise the error will be
584  * written to stderr.
585  *
586  * Params:
587  *  file = The name of the file that signaled this error.
588  *  line = The line number on which this error occurred.
589  *  msg  = An error message supplied by the user.
590  */
onUnittestErrorMsg(string file,size_t line,string msg)591 extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothrow
592 {
593     onAssertErrorMsg( file, line, msg );
594 }
595 
596 
597 ///////////////////////////////////////////////////////////////////////////////
598 // Internal Error Callbacks
599 ///////////////////////////////////////////////////////////////////////////////
600 
601 /**
602  * A callback for general array bounds errors in D. A $(LREF RangeError) will be thrown.
603  *
604  * Params:
605  *  file = The name of the file that signaled this error.
606  *  line = The line number on which this error occurred.
607  *
608  * Throws:
609  *  $(LREF RangeError).
610  */
611 extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
612 {
613     throw staticError!RangeError(file, line, null);
614 }
615 
616 /**
617  * A callback for array slice out of bounds errors in D.
618  *
619  * Params:
620  *  lower  = the lower bound of the index passed of a slice
621  *  upper  = the upper bound of the index passed of a slice or the index if not a slice
622  *  length = length of the array
623  *  file = The name of the file that signaled this error.
624  *  line = The line number on which this error occurred.
625  *
626  * Throws:
627  *  $(LREF ArraySliceError).
628  */
629 extern (C) void onArraySliceError( size_t lower = 0, size_t upper = 0, size_t length = 0,
630                               string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
631 {
632     throw staticError!ArraySliceError(lower, upper, length, file, line, null);
633 }
634 
635 /**
636  * A callback for array index out of bounds errors in D.
637  *
638  * Params:
639  *  index  = index in the array
640  *  length = length of the array
641  *  file = The name of the file that signaled this error.
642  *  line = The line number on which this error occurred.
643  *
644  * Throws:
645  *  $(LREF ArrayIndexError).
646  */
647 extern (C) void onArrayIndexError( size_t index = 0, size_t length = 0,
648                               string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
649 {
650     throw staticError!ArrayIndexError(index, length, file, line, null);
651 }
652 
653 /**
654  * A callback for finalize errors in D.  A $(LREF FinalizeError) will be thrown.
655  *
656  * Params:
657  *  info = The TypeInfo instance for the object that failed finalization.
658  *  e = The exception thrown during finalization.
659  *  file = The name of the file that signaled this error.
660  *  line = The line number on which this error occurred.
661  *
662  * Throws:
663  *  $(LREF FinalizeError).
664  */
665 extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
666 {
667     // This error is thrown during a garbage collection, so no allocation must occur while
668     //  generating this object. So we use a preallocated instance
669     throw staticError!FinalizeError(info, e, file, line);
670 }
671 
version(D_BetterC)672 version (D_BetterC)
673 {
674     // When compiling with -betterC we use template functions so if they are
675     // used the bodies are copied into the user's program so there is no need
676     // for the D runtime during linking.
677 
678     // In the future we might want to convert all functions in this module to
679     // templates even for ordinary builds instead of providing them as an
680     // extern(C) library.
681 
682     void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
683     {
684         assert(0, "Memory allocation failed");
685     }
686     alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
687 
688     void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
689     {
690         assert(0, "Invalid memory operation");
691     }
692 }
693 else
694 {
695     /**
696      * A callback for out of memory errors in D.  An $(LREF OutOfMemoryError) will be
697      * thrown.
698      *
699      * Throws:
700      *  $(LREF OutOfMemoryError).
701      */
702     extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
703     {
704         // NOTE: Since an out of memory condition exists, no allocation must occur
705         //       while generating this object.
706         throw staticError!OutOfMemoryError();
707     }
708 
onOutOfMemoryErrorNoGC()709     extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
710     {
711         // suppress stacktrace until they are @nogc
712         throw staticError!OutOfMemoryError(false);
713     }
714 }
715 
716 /**
717  * A callback for invalid memory operations in D.  An
718  * $(LREF InvalidMemoryOperationError) will be thrown.
719  *
720  * Throws:
721  *  $(LREF InvalidMemoryOperationError).
722  */
723 extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
724 {
725     // The same restriction applies as for onOutOfMemoryError. The GC is in an
726     // undefined state, thus no allocation must occur while generating this object.
727     throw staticError!InvalidMemoryOperationError();
728 }
729 
730 
731 /**
732  * A callback for errors in the case of a failed fork in D.  A $(LREF ForkError) will be thrown.
733  *
734  * Params:
735  *  file = The name of the file that signaled this error.
736  *  line = The line number on which this error occurred.
737  *
738  * Throws:
739  *  $(LREF ConfigurationError).
740  */
741 extern (C) void onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
742 {
743     throw staticError!ForkError( file, line, null );
744 }
745 
746 /**
747  * A callback for unicode errors in D.  A $(LREF UnicodeException) will be thrown.
748  *
749  * Params:
750  *  msg = Information about the error.
751  *  idx = String index where this error was detected.
752  *  file = The name of the file that signaled this error.
753  *  line = The line number on which this error occurred.
754  *
755  * Throws:
756  *  $(LREF UnicodeException).
757  */
758 extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure
759 {
760     throw new UnicodeException( msg, idx, file, line );
761 }
762 
763 /***********************************
764  * These functions must be defined for any D program linked
765  * against this library.
766  */
767 /+
768 extern (C) void onAssertError(string file, size_t line);
769 extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
770 extern (C) void onUnittestErrorMsg(string file, size_t line, string msg);
771 extern (C) void onRangeError(string file, size_t line);
772 extern (C) void onHiddenFuncError(Object o);
773 +/
774 
775 /***********************************
776  * Function calls to these are generated by the compiler and inserted into
777  * the object code.
778  */
779 
780 extern (C)
781 {
782     /* One of these three is called upon an assert() fail.
783      */
_d_assertp(immutable (char)* file,uint line)784     void _d_assertp(immutable(char)* file, uint line)
785     {
786         import core.stdc.string : strlen;
787         onAssertError(file[0 .. strlen(file)], line);
788     }
789 
_d_assert_msg(string msg,string file,uint line)790     void _d_assert_msg(string msg, string file, uint line)
791     {
792         onAssertErrorMsg(file, line, msg);
793     }
794 
_d_assert(string file,uint line)795     void _d_assert(string file, uint line)
796     {
797         onAssertError(file, line);
798     }
799 
800     /* One of these three is called upon an assert() fail inside of a unittest block
801      */
_d_unittestp(immutable (char)* file,uint line)802     void _d_unittestp(immutable(char)* file, uint line)
803     {
804         import core.stdc.string : strlen;
805         _d_unittest(file[0 .. strlen(file)], line);
806     }
807 
_d_unittest_msg(string msg,string file,uint line)808     void _d_unittest_msg(string msg, string file, uint line)
809     {
810         onUnittestErrorMsg(file, line, msg);
811     }
812 
_d_unittest(string file,uint line)813     void _d_unittest(string file, uint line)
814     {
815         _d_unittest_msg("unittest failure", file, line);
816     }
817 
818     /// Called when an invalid array index/slice or associative array key is accessed
_d_arrayboundsp(immutable (char *)file,uint line)819     void _d_arrayboundsp(immutable(char*) file, uint line)
820     {
821         import core.stdc.string : strlen;
822         onRangeError(file[0 .. strlen(file)], line);
823     }
824 
825     /// ditto
_d_arraybounds(string file,uint line)826     void _d_arraybounds(string file, uint line)
827     {
828         onRangeError(file, line);
829     }
830 
831     /// Called when an out of range slice of an array is created
_d_arraybounds_slicep(immutable (char *)file,uint line,size_t lower,size_t upper,size_t length)832     void _d_arraybounds_slicep(immutable(char*) file, uint line, size_t lower, size_t upper, size_t length)
833     {
834         import core.stdc.string : strlen;
835         onArraySliceError(lower, upper, length, file[0 .. strlen(file)], line);
836     }
837 
838     /// ditto
_d_arraybounds_slice(string file,uint line,size_t lower,size_t upper,size_t length)839     void _d_arraybounds_slice(string file, uint line, size_t lower, size_t upper, size_t length)
840     {
841         onArraySliceError(lower, upper, length, file, line);
842     }
843 
844     /// Called when an out of range array index is accessed
_d_arraybounds_indexp(immutable (char *)file,uint line,size_t index,size_t length)845     void _d_arraybounds_indexp(immutable(char*) file, uint line, size_t index, size_t length)
846     {
847         import core.stdc.string : strlen;
848         onArrayIndexError(index, length, file[0 .. strlen(file)], line);
849     }
850 
851     /// ditto
_d_arraybounds_index(string file,uint line,size_t index,size_t length)852     void _d_arraybounds_index(string file, uint line, size_t index, size_t length)
853     {
854         onArrayIndexError(index, length, file, line);
855     }
856 }
857 
858 // TLS storage shared for all errors, chaining might create circular reference
859 private align(2 * size_t.sizeof) void[256] _store;
860 
861 // only Errors for now as those are rarely chained
862 private T staticError(T, Args...)(auto ref Args args)
863     if (is(T : Error))
864 {
865     // pure hack, what we actually need is @noreturn and allow to call that in pure functions
get()866     static T get()
867     {
868         static assert(__traits(classInstanceSize, T) <= _store.length,
869                       T.stringof ~ " is too large for staticError()");
870 
871         return cast(T) _store.ptr;
872     }
873     auto res = (cast(T function() @trusted pure nothrow @nogc) &get)();
874     import core.lifetime : emplace;
875     emplace(res, args);
876     return res;
877 }
878 
879 // Suppress traceinfo generation when the GC cannot be used.  Workaround for
880 // Bugzilla 14993. We should make stack traces @nogc instead.
881 package class SuppressTraceInfo : Throwable.TraceInfo
882 {
opApply(scope int delegate (ref const (char[])))883     override int opApply(scope int delegate(ref const(char[]))) const { return 0; }
opApply(scope int delegate (ref size_t,ref const (char[])))884     override int opApply(scope int delegate(ref size_t, ref const(char[]))) const { return 0; }
toString()885     override string toString() const { return null; }
instance()886     static SuppressTraceInfo instance() @trusted @nogc pure nothrow
887     {
888         static immutable SuppressTraceInfo it = new SuppressTraceInfo;
889         return cast(SuppressTraceInfo)it;
890     }
891 }
892