123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891 |
- /**
- The exception module defines all system-level exceptions and provides a
- mechanism to alter system-level error handling.
- Copyright: Copyright Sean Kelly 2005 - 2013.
- License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
- Authors: Sean Kelly and $(HTTP jmdavisprog.com, Jonathan M Davis)
- Source: $(DRUNTIMESRC core/_exception.d)
- */
- module core.exception;
- // Compiler lowers final switch default case to this (which is a runtime error)
- void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
- {
- // Consider making this a compile time check.
- version (D_Exceptions)
- throw staticError!SwitchError(file, line, null);
- else
- assert(0, "No appropriate switch clause found");
- }
- version (D_BetterC)
- {
- // When compiling with -betterC we use template functions so if they are
- // used the bodies are copied into the user's program so there is no need
- // for the D runtime during linking.
- // In the future we might want to convert all functions in this module to
- // templates even for ordinary builds instead of providing them as an
- // extern(C) library.
- void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
- {
- assert(0, "Memory allocation failed");
- }
- alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
- void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
- {
- assert(0, "Invalid memory operation");
- }
- }
- else:
- /**
- * Thrown on a range error.
- */
- class RangeError : Error
- {
- this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
- {
- super( "Range violation", file, line, next );
- }
- protected this( string msg, string file, size_t line, Throwable next = null ) @nogc nothrow pure @safe
- {
- super( msg, file, line, next );
- }
- }
- unittest
- {
- {
- auto re = new RangeError();
- assert(re.file == __FILE__);
- assert(re.line == __LINE__ - 2);
- assert(re.next is null);
- assert(re.msg == "Range violation");
- }
- {
- auto re = new RangeError("hello", 42, new Exception("It's an Exception!"));
- assert(re.file == "hello");
- assert(re.line == 42);
- assert(re.next !is null);
- assert(re.msg == "Range violation");
- }
- }
- /**
- * Thrown when an out of bounds array index is accessed.
- */
- class ArrayIndexError : RangeError
- {
- /// Index into array
- const size_t index;
- /// Length of indexed array
- const size_t length;
- // Buffer to avoid GC allocations
- private immutable char[100] msgBuf = '\0';
- this(size_t index, size_t length, string file = __FILE__,
- size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
- {
- this.index = index;
- this.length = length;
- // Constructing the message is a bit clumsy:
- // It's essentially `printf("index [%zu] is out of bounds for array of length [%zu]", index, length)`,
- // but even `snprintf` isn't `pure`.
- // Also string concatenation isn't `@nogc`, and casting to/from immutable isn't `@safe`
- import core.internal.string : unsignedToTempString;
- char[msgBuf.length] buf = void;
- char[20] tmpBuf = void;
- char[] sink = buf[];
- sink.rangeMsgPut("index [");
- sink.rangeMsgPut(unsignedToTempString!10(index, tmpBuf));
- sink.rangeMsgPut("] is out of bounds for array of length ");
- sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
- this.msgBuf = buf;
- super(msgBuf[0..$-sink.length], file, line, next);
- }
- }
- @safe pure unittest
- {
- assert(new ArrayIndexError(900, 700).msg == "index [900] is out of bounds for array of length 700");
- // Ensure msg buffer doesn't overflow on large numbers
- assert(new ArrayIndexError(size_t.max, size_t.max-1).msg);
- }
- unittest
- {
- try
- {
- _d_arraybounds_indexp("test", 400, 9, 3);
- assert(0, "no ArrayIndexError thrown");
- }
- catch (ArrayIndexError re)
- {
- assert(re.file == "test");
- assert(re.line == 400);
- assert(re.index == 9);
- assert(re.length == 3);
- }
- }
- /**
- * Thrown when an out of bounds array slice is created
- */
- class ArraySliceError : RangeError
- {
- /// Lower/upper bound passed to slice: `array[lower .. upper]`
- const size_t lower, upper;
- /// Length of sliced array
- const size_t length;
- private immutable char[120] msgBuf = '\0';
- this(size_t lower, size_t upper, size_t length, string file = __FILE__,
- size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
- {
- this.lower = lower;
- this.upper = upper;
- this.length = length;
- // Constructing the message is a bit clumsy for the same reasons as ArrayIndexError
- import core.internal.string : unsignedToTempString;
- char[msgBuf.length] buf = void;
- char[20] tmpBuf = void;
- char[] sink = buf;
- sink.rangeMsgPut("slice [");
- sink.rangeMsgPut(unsignedToTempString!10(lower, tmpBuf));
- sink.rangeMsgPut(" .. ");
- sink.rangeMsgPut(unsignedToTempString!10(upper, tmpBuf));
- sink.rangeMsgPut("] ");
- if (lower > upper)
- {
- sink.rangeMsgPut("has a larger lower index than upper index");
- }
- else
- {
- sink.rangeMsgPut("extends past source array of length ");
- sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
- }
- this.msgBuf = buf;
- super(msgBuf[0..$-sink.length], file, line, next);
- }
- }
- @safe pure unittest
- {
- assert(new ArraySliceError(40, 80, 20).msg == "slice [40 .. 80] extends past source array of length 20");
- assert(new ArraySliceError(90, 70, 20).msg == "slice [90 .. 70] has a larger lower index than upper index");
- // Ensure msg buffer doesn't overflow on large numbers
- assert(new ArraySliceError(size_t.max, size_t.max, size_t.max-1).msg);
- }
- unittest
- {
- try
- {
- _d_arraybounds_slicep("test", 400, 1, 7, 3);
- assert(0, "no ArraySliceError thrown");
- }
- catch (ArraySliceError re)
- {
- assert(re.file == "test");
- assert(re.line == 400);
- assert(re.lower == 1);
- assert(re.upper == 7);
- assert(re.length == 3);
- }
- }
- /// Mini `std.range.primitives: put` for constructor of ArraySliceError / ArrayIndexError
- private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure @safe
- {
- assert(r.length >= e.length); // don't throw ArraySliceError inside ArrayIndexError ctor
- r[0 .. e.length] = e[];
- r = r[e.length .. $];
- }
- /**
- * Thrown on an assert error.
- */
- class AssertError : Error
- {
- @safe pure nothrow this( string file, size_t line )
- {
- this(cast(Throwable)null, file, line);
- }
- @safe pure nothrow this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
- {
- this( "Assertion failure", file, line, next);
- }
- @safe pure nothrow this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
- {
- super( msg, file, line, next );
- }
- }
- unittest
- {
- {
- auto ae = new AssertError("hello", 42);
- assert(ae.file == "hello");
- assert(ae.line == 42);
- assert(ae.next is null);
- assert(ae.msg == "Assertion failure");
- }
- {
- auto ae = new AssertError(new Exception("It's an Exception!"));
- assert(ae.file == __FILE__);
- assert(ae.line == __LINE__ - 2);
- assert(ae.next !is null);
- assert(ae.msg == "Assertion failure");
- }
- {
- auto ae = new AssertError(new Exception("It's an Exception!"), "hello", 42);
- assert(ae.file == "hello");
- assert(ae.line == 42);
- assert(ae.next !is null);
- assert(ae.msg == "Assertion failure");
- }
- {
- auto ae = new AssertError("msg");
- assert(ae.file == __FILE__);
- assert(ae.line == __LINE__ - 2);
- assert(ae.next is null);
- assert(ae.msg == "msg");
- }
- {
- auto ae = new AssertError("msg", "hello", 42);
- assert(ae.file == "hello");
- assert(ae.line == 42);
- assert(ae.next is null);
- assert(ae.msg == "msg");
- }
- {
- auto ae = new AssertError("msg", "hello", 42, new Exception("It's an Exception!"));
- assert(ae.file == "hello");
- assert(ae.line == 42);
- assert(ae.next !is null);
- assert(ae.msg == "msg");
- }
- }
- /**
- * Thrown on finalize error.
- */
- class FinalizeError : Error
- {
- TypeInfo info;
- this( TypeInfo ci, Throwable next, string file = __FILE__, size_t line = __LINE__ ) @safe pure nothrow @nogc
- {
- this(ci, file, line, next);
- }
- this( TypeInfo ci, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
- {
- super( "Finalization error", file, line, next );
- super.info = SuppressTraceInfo.instance;
- info = ci;
- }
- override string toString() const @safe
- {
- return "An exception was thrown while finalizing an instance of " ~ info.toString();
- }
- }
- unittest
- {
- ClassInfo info = new ClassInfo;
- info.name = "testInfo";
- {
- auto fe = new FinalizeError(info);
- assert(fe.file == __FILE__);
- assert(fe.line == __LINE__ - 2);
- assert(fe.next is null);
- assert(fe.msg == "Finalization error");
- assert(fe.info == info);
- }
- {
- auto fe = new FinalizeError(info, new Exception("It's an Exception!"));
- assert(fe.file == __FILE__);
- assert(fe.line == __LINE__ - 2);
- assert(fe.next !is null);
- assert(fe.msg == "Finalization error");
- assert(fe.info == info);
- }
- {
- auto fe = new FinalizeError(info, "hello", 42);
- assert(fe.file == "hello");
- assert(fe.line == 42);
- assert(fe.next is null);
- assert(fe.msg == "Finalization error");
- assert(fe.info == info);
- }
- {
- auto fe = new FinalizeError(info, "hello", 42, new Exception("It's an Exception!"));
- assert(fe.file == "hello");
- assert(fe.line == 42);
- assert(fe.next !is null);
- assert(fe.msg == "Finalization error");
- assert(fe.info == info);
- }
- }
- /**
- * Thrown on an out of memory error.
- */
- class OutOfMemoryError : Error
- {
- this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
- {
- this(true, file, line, next);
- }
- this(bool trace, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
- {
- super("Memory allocation failed", file, line, next);
- if (!trace)
- this.info = SuppressTraceInfo.instance;
- }
- override string toString() const @trusted
- {
- return msg.length ? (cast()this).superToString() : "Memory allocation failed";
- }
- // kludge to call non-const super.toString
- private string superToString() @trusted
- {
- return super.toString();
- }
- }
- unittest
- {
- {
- auto oome = new OutOfMemoryError();
- assert(oome.file == __FILE__);
- assert(oome.line == __LINE__ - 2);
- assert(oome.next is null);
- assert(oome.msg == "Memory allocation failed");
- assert(oome.toString.length);
- }
- {
- auto oome = new OutOfMemoryError("hello", 42, new Exception("It's an Exception!"));
- assert(oome.file == "hello");
- assert(oome.line == 42);
- assert(oome.next !is null);
- assert(oome.msg == "Memory allocation failed");
- }
- }
- /**
- * Thrown on an invalid memory operation.
- *
- * An invalid memory operation error occurs in circumstances when the garbage
- * collector has detected an operation it cannot reliably handle. The default
- * D GC is not re-entrant, so this can happen due to allocations done from
- * within finalizers called during a garbage collection cycle.
- */
- class InvalidMemoryOperationError : Error
- {
- this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
- {
- super( "Invalid memory operation", file, line, next );
- this.info = SuppressTraceInfo.instance;
- }
- override string toString() const @trusted
- {
- return msg.length ? (cast()this).superToString() : "Invalid memory operation";
- }
- // kludge to call non-const super.toString
- private string superToString() @trusted
- {
- return super.toString();
- }
- }
- unittest
- {
- {
- auto oome = new InvalidMemoryOperationError();
- assert(oome.file == __FILE__);
- assert(oome.line == __LINE__ - 2);
- assert(oome.next is null);
- assert(oome.msg == "Invalid memory operation");
- assert(oome.toString.length);
- }
- {
- auto oome = new InvalidMemoryOperationError("hello", 42, new Exception("It's an Exception!"));
- assert(oome.file == "hello");
- assert(oome.line == 42);
- assert(oome.next !is null);
- assert(oome.msg == "Invalid memory operation");
- }
- }
- /**
- * Thrown on a configuration error.
- */
- class ForkError : Error
- {
- this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe
- {
- super( "fork() failed", file, line, next );
- }
- }
- /**
- * Thrown on a switch error.
- */
- class SwitchError : Error
- {
- @safe pure nothrow @nogc this( string file = __FILE__, size_t line = __LINE__, Throwable next = null )
- {
- super( "No appropriate switch clause found", file, line, next );
- }
- }
- unittest
- {
- {
- auto se = new SwitchError();
- assert(se.file == __FILE__);
- assert(se.line == __LINE__ - 2);
- assert(se.next is null);
- assert(se.msg == "No appropriate switch clause found");
- }
- {
- auto se = new SwitchError("hello", 42, new Exception("It's an Exception!"));
- assert(se.file == "hello");
- assert(se.line == 42);
- assert(se.next !is null);
- assert(se.msg == "No appropriate switch clause found");
- }
- }
- /**
- * Thrown on a unicode conversion error.
- */
- class UnicodeException : Exception
- {
- size_t idx;
- this( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc
- {
- super( msg, file, line, next );
- this.idx = idx;
- }
- }
- unittest
- {
- {
- auto ue = new UnicodeException("msg", 2);
- assert(ue.file == __FILE__);
- assert(ue.line == __LINE__ - 2);
- assert(ue.next is null);
- assert(ue.msg == "msg");
- assert(ue.idx == 2);
- }
- {
- auto ue = new UnicodeException("msg", 2, "hello", 42, new Exception("It's an Exception!"));
- assert(ue.file == "hello");
- assert(ue.line == 42);
- assert(ue.next !is null);
- assert(ue.msg == "msg");
- assert(ue.idx == 2);
- }
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Overrides
- ///////////////////////////////////////////////////////////////////////////////
- // NOTE: One assert handler is used for all threads. Thread-local
- // behavior should occur within the handler itself. This delegate
- // is __gshared for now based on the assumption that it will only
- // set by the main thread during program initialization.
- private __gshared AssertHandler _assertHandler = null;
- /**
- Gets/sets assert hander. null means the default handler is used.
- */
- alias AssertHandler = void function(string file, size_t line, string msg) nothrow;
- /// ditto
- @property AssertHandler assertHandler() @trusted nothrow @nogc
- {
- return _assertHandler;
- }
- /// ditto
- @property void assertHandler(AssertHandler handler) @trusted nothrow @nogc
- {
- _assertHandler = handler;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Overridable Callbacks
- ///////////////////////////////////////////////////////////////////////////////
- /**
- * A callback for assert errors in D. The user-supplied assert handler will
- * be called if one has been supplied, otherwise an $(LREF AssertError) will be
- * thrown.
- *
- * Params:
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- */
- extern (C) void onAssertError( string file = __FILE__, size_t line = __LINE__ ) nothrow
- {
- if ( _assertHandler is null )
- throw staticError!AssertError(file, line);
- _assertHandler( file, line, null);
- }
- /**
- * A callback for assert errors in D. The user-supplied assert handler will
- * be called if one has been supplied, otherwise an $(LREF AssertError) will be
- * thrown.
- *
- * Params:
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- * msg = An error message supplied by the user.
- */
- extern (C) void onAssertErrorMsg( string file, size_t line, string msg ) nothrow
- {
- if ( _assertHandler is null )
- throw staticError!AssertError(msg, file, line);
- _assertHandler( file, line, msg );
- }
- /**
- * A callback for unittest errors in D. The user-supplied unittest handler
- * will be called if one has been supplied, otherwise the error will be
- * written to stderr.
- *
- * Params:
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- * msg = An error message supplied by the user.
- */
- extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothrow
- {
- onAssertErrorMsg( file, line, msg );
- }
- ///////////////////////////////////////////////////////////////////////////////
- // Internal Error Callbacks
- ///////////////////////////////////////////////////////////////////////////////
- /**
- * A callback for general array bounds errors in D. A $(LREF RangeError) will be thrown.
- *
- * Params:
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- *
- * Throws:
- * $(LREF RangeError).
- */
- extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
- {
- throw staticError!RangeError(file, line, null);
- }
- /**
- * A callback for array slice out of bounds errors in D.
- *
- * Params:
- * lower = the lower bound of the index passed of a slice
- * upper = the upper bound of the index passed of a slice or the index if not a slice
- * length = length of the array
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- *
- * Throws:
- * $(LREF ArraySliceError).
- */
- extern (C) void onArraySliceError( size_t lower = 0, size_t upper = 0, size_t length = 0,
- string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
- {
- throw staticError!ArraySliceError(lower, upper, length, file, line, null);
- }
- /**
- * A callback for array index out of bounds errors in D.
- *
- * Params:
- * index = index in the array
- * length = length of the array
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- *
- * Throws:
- * $(LREF ArrayIndexError).
- */
- extern (C) void onArrayIndexError( size_t index = 0, size_t length = 0,
- string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
- {
- throw staticError!ArrayIndexError(index, length, file, line, null);
- }
- /**
- * A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown.
- *
- * Params:
- * info = The TypeInfo instance for the object that failed finalization.
- * e = The exception thrown during finalization.
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- *
- * Throws:
- * $(LREF FinalizeError).
- */
- extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow
- {
- // This error is thrown during a garbage collection, so no allocation must occur while
- // generating this object. So we use a preallocated instance
- throw staticError!FinalizeError(info, e, file, line);
- }
- /**
- * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be
- * thrown.
- *
- * Throws:
- * $(LREF OutOfMemoryError).
- */
- extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
- {
- // NOTE: Since an out of memory condition exists, no allocation must occur
- // while generating this object.
- throw staticError!OutOfMemoryError();
- }
- extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
- {
- // suppress stacktrace until they are @nogc
- throw staticError!OutOfMemoryError(false);
- }
- /**
- * A callback for invalid memory operations in D. An
- * $(LREF InvalidMemoryOperationError) will be thrown.
- *
- * Throws:
- * $(LREF InvalidMemoryOperationError).
- */
- extern (C) void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
- {
- // The same restriction applies as for onOutOfMemoryError. The GC is in an
- // undefined state, thus no allocation must occur while generating this object.
- throw staticError!InvalidMemoryOperationError();
- }
- /**
- * A callback for errors in the case of a failed fork in D. A $(LREF ForkError) will be thrown.
- *
- * Params:
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- *
- * Throws:
- * $(LREF ConfigurationError).
- */
- extern (C) void onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
- {
- throw staticError!ForkError( file, line, null );
- }
- /**
- * A callback for unicode errors in D. A $(LREF UnicodeException) will be thrown.
- *
- * Params:
- * msg = Information about the error.
- * idx = String index where this error was detected.
- * file = The name of the file that signaled this error.
- * line = The line number on which this error occurred.
- *
- * Throws:
- * $(LREF UnicodeException).
- */
- extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure
- {
- throw new UnicodeException( msg, idx, file, line );
- }
- /***********************************
- * These functions must be defined for any D program linked
- * against this library.
- */
- /+
- extern (C) void onAssertError(string file, size_t line);
- extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
- extern (C) void onUnittestErrorMsg(string file, size_t line, string msg);
- extern (C) void onRangeError(string file, size_t line);
- extern (C) void onHiddenFuncError(Object o);
- +/
- /***********************************
- * Function calls to these are generated by the compiler and inserted into
- * the object code.
- */
- extern (C)
- {
- /* One of these three is called upon an assert() fail.
- */
- void _d_assertp(immutable(char)* file, uint line)
- {
- import core.stdc.string : strlen;
- onAssertError(file[0 .. strlen(file)], line);
- }
- void _d_assert_msg(string msg, string file, uint line)
- {
- onAssertErrorMsg(file, line, msg);
- }
- void _d_assert(string file, uint line)
- {
- onAssertError(file, line);
- }
- /* One of these three is called upon an assert() fail inside of a unittest block
- */
- void _d_unittestp(immutable(char)* file, uint line)
- {
- import core.stdc.string : strlen;
- _d_unittest(file[0 .. strlen(file)], line);
- }
- void _d_unittest_msg(string msg, string file, uint line)
- {
- onUnittestErrorMsg(file, line, msg);
- }
- void _d_unittest(string file, uint line)
- {
- _d_unittest_msg("unittest failure", file, line);
- }
- /// Called when an invalid array index/slice or associative array key is accessed
- void _d_arrayboundsp(immutable(char*) file, uint line)
- {
- import core.stdc.string : strlen;
- onRangeError(file[0 .. strlen(file)], line);
- }
- /// ditto
- void _d_arraybounds(string file, uint line)
- {
- onRangeError(file, line);
- }
- /// Called when an out of range slice of an array is created
- void _d_arraybounds_slicep(immutable(char*) file, uint line, size_t lower, size_t upper, size_t length)
- {
- import core.stdc.string : strlen;
- onArraySliceError(lower, upper, length, file[0 .. strlen(file)], line);
- }
- /// ditto
- void _d_arraybounds_slice(string file, uint line, size_t lower, size_t upper, size_t length)
- {
- onArraySliceError(lower, upper, length, file, line);
- }
- /// Called when an out of range array index is accessed
- void _d_arraybounds_indexp(immutable(char*) file, uint line, size_t index, size_t length)
- {
- import core.stdc.string : strlen;
- onArrayIndexError(index, length, file[0 .. strlen(file)], line);
- }
- /// ditto
- void _d_arraybounds_index(string file, uint line, size_t index, size_t length)
- {
- onArrayIndexError(index, length, file, line);
- }
- }
- // TLS storage shared for all errors, chaining might create circular reference
- private align(2 * size_t.sizeof) void[256] _store;
- // only Errors for now as those are rarely chained
- private T staticError(T, Args...)(auto ref Args args)
- if (is(T : Error))
- {
- // pure hack, what we actually need is @noreturn and allow to call that in pure functions
- static T get()
- {
- static assert(__traits(classInstanceSize, T) <= _store.length,
- T.stringof ~ " is too large for staticError()");
- return cast(T) _store.ptr;
- }
- auto res = (cast(T function() @trusted pure nothrow @nogc) &get)();
- import core.lifetime : emplace;
- emplace(res, args);
- return res;
- }
- // Suppress traceinfo generation when the GC cannot be used. Workaround for
- // Bugzilla 14993. We should make stack traces @nogc instead.
- package class SuppressTraceInfo : Throwable.TraceInfo
- {
- override int opApply(scope int delegate(ref const(char[]))) const { return 0; }
- override int opApply(scope int delegate(ref size_t, ref const(char[]))) const { return 0; }
- override string toString() const { return null; }
- static SuppressTraceInfo instance() @trusted @nogc pure nothrow
- {
- static immutable SuppressTraceInfo it = new SuppressTraceInfo;
- return cast(SuppressTraceInfo)it;
- }
- }
|