The OpenD Programming Language

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