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 * 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 } 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 } 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 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 { 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 info = ci; 282 } 283 284 override string toString() const @safe 285 { 286 return "An exception was thrown while finalizing an instance of " ~ info.toString(); 287 } 288 } 289 290 unittest 291 { 292 ClassInfo info = new ClassInfo; 293 info.name = "testInfo"; 294 295 { 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); 302 } 303 304 { 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); 311 } 312 313 { 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); 320 } 321 322 { 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); 329 } 330 } 331 332 /** 333 * Thrown on an out of memory error. 334 */ 335 class OutOfMemoryError : Error 336 { 337 this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc 338 { 339 this(true, file, line, next); 340 } 341 342 this(bool trace, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc 343 { 344 super("Memory allocation failed", file, line, next); 345 if (!trace) 346 this.info = SuppressTraceInfo.instance; 347 } 348 349 override string toString() const @trusted 350 { 351 return msg.length ? (cast()this).superToString() : "Memory allocation failed"; 352 } 353 354 // kludge to call non-const super.toString 355 private string superToString() @trusted 356 { 357 return super.toString(); 358 } 359 } 360 361 unittest 362 { 363 { 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); 370 } 371 372 { 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"); 378 } 379 } 380 381 382 /** 383 * Thrown on an invalid memory operation. 384 * 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. 389 */ 390 class InvalidMemoryOperationError : Error 391 { 392 this(string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc 393 { 394 super( "Invalid memory operation", file, line, next ); 395 } 396 397 override string toString() const @trusted 398 { 399 return msg.length ? (cast()this).superToString() : "Invalid memory operation"; 400 } 401 402 // kludge to call non-const super.toString 403 private string superToString() @trusted 404 { 405 return super.toString(); 406 } 407 } 408 409 unittest 410 { 411 { 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); 418 } 419 420 { 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"); 426 } 427 } 428 429 430 /** 431 * Thrown on a configuration error. 432 */ 433 class ForkError : Error 434 { 435 this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @nogc nothrow pure @safe 436 { 437 super( "fork() failed", file, line, next ); 438 } 439 } 440 441 442 /** 443 * Thrown on a switch error. 444 */ 445 class SwitchError : Error 446 { 447 @safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) 448 { 449 super( msg, file, line, next ); 450 } 451 } 452 453 unittest 454 { 455 { 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"); 461 } 462 463 { 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"); 469 } 470 } 471 472 473 /** 474 * Thrown on a unicode conversion error. 475 */ 476 class UnicodeException : Exception 477 { 478 size_t idx; 479 480 this( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) @safe pure nothrow @nogc 481 { 482 super( msg, file, line, next ); 483 this.idx = idx; 484 } 485 } 486 487 unittest 488 { 489 { 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); 496 } 497 498 { 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); 505 } 506 } 507 508 509 /////////////////////////////////////////////////////////////////////////////// 510 // Overrides 511 /////////////////////////////////////////////////////////////////////////////// 512 513 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; 519 520 521 /** 522 Gets/sets assert hander. null means the default handler is used. 523 */ 524 alias AssertHandler = void function(string file, size_t line, string msg) nothrow; 525 526 /// ditto 527 @property AssertHandler assertHandler() @trusted nothrow @nogc 528 { 529 return _assertHandler; 530 } 531 532 /// ditto 533 @property void assertHandler(AssertHandler handler) @trusted nothrow @nogc 534 { 535 _assertHandler = handler; 536 } 537 538 539 /////////////////////////////////////////////////////////////////////////////// 540 // Overridable Callbacks 541 /////////////////////////////////////////////////////////////////////////////// 542 543 544 /** 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. 548 * 549 * Params: 550 * file = The name of the file that signaled this error. 551 * line = The line number on which this error occurred. 552 */ 553 extern (C) void onAssertError( string file = __FILE__, size_t line = __LINE__ ) nothrow 554 { 555 if ( _assertHandler is null ) 556 throw staticError!AssertError(file, line); 557 _assertHandler( file, line, null); 558 } 559 560 561 /** 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. 565 * 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. 570 */ 571 extern (C) void onAssertErrorMsg( string file, size_t line, string msg ) nothrow 572 { 573 if ( _assertHandler is null ) 574 throw staticError!AssertError(msg, file, line); 575 _assertHandler( file, line, msg ); 576 } 577 578 579 /** 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. 583 * 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. 588 */ 589 extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothrow 590 { 591 onAssertErrorMsg( file, line, msg ); 592 } 593 594 595 /////////////////////////////////////////////////////////////////////////////// 596 // Internal Error Callbacks 597 /////////////////////////////////////////////////////////////////////////////// 598 599 /** 600 * A callback for general array bounds errors in D. A $(LREF RangeError) will be thrown. 601 * 602 * Params: 603 * file = The name of the file that signaled this error. 604 * line = The line number on which this error occurred. 605 * 606 * Throws: 607 * $(LREF RangeError). 608 */ 609 extern (C) noreturn onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc 610 { 611 throw staticError!RangeError(file, line, null); 612 } 613 614 /** 615 * A callback for array slice out of bounds errors in D. 616 * 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. 623 * 624 * Throws: 625 * $(LREF ArraySliceError). 626 */ 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 629 { 630 throw staticError!ArraySliceError(lower, upper, length, file, line, null); 631 } 632 633 /** 634 * A callback for array index out of bounds errors in D. 635 * 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. 641 * 642 * Throws: 643 * $(LREF ArrayIndexError). 644 */ 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 647 { 648 throw staticError!ArrayIndexError(index, length, file, line, null); 649 } 650 651 /** 652 * A callback for finalize errors in D. A $(LREF FinalizeError) will be thrown. 653 * 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. 659 * 660 * Throws: 661 * $(LREF FinalizeError). 662 */ 663 extern (C) noreturn onFinalizeError( TypeInfo info, Throwable e, string file = __FILE__, size_t line = __LINE__ ) @trusted nothrow 664 { 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); 668 } 669 670 version (D_BetterC) 671 { 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. 675 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. 679 680 noreturn onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted 681 { 682 assert(0, "Memory allocation failed"); 683 } 684 alias onOutOfMemoryErrorNoGC = onOutOfMemoryError; 685 686 noreturn onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted 687 { 688 assert(0, "Invalid memory operation"); 689 } 690 } 691 else 692 { 693 /** 694 * A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be 695 * thrown. 696 * 697 * Throws: 698 * $(LREF OutOfMemoryError). 699 */ 700 extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ 701 { 702 // NOTE: Since an out of memory condition exists, no allocation must occur 703 // while generating this object. 704 throw staticError!OutOfMemoryError(); 705 } 706 707 extern (C) noreturn onOutOfMemoryErrorNoGC() @trusted nothrow @nogc 708 { 709 // suppress stacktrace until they are @nogc 710 throw staticError!OutOfMemoryError(false); 711 } 712 } 713 714 /** 715 * A callback for invalid memory operations in D. An 716 * $(LREF InvalidMemoryOperationError) will be thrown. 717 * 718 * Throws: 719 * $(LREF InvalidMemoryOperationError). 720 */ 721 extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */ 722 { 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(); 726 } 727 728 729 /** 730 * A callback for errors in the case of a failed fork in D. A $(LREF ForkError) will be thrown. 731 * 732 * Params: 733 * file = The name of the file that signaled this error. 734 * line = The line number on which this error occurred. 735 * 736 * Throws: 737 * $(LREF ConfigurationError). 738 */ 739 extern (C) noreturn onForkError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc 740 { 741 throw staticError!ForkError( file, line, null ); 742 } 743 744 /** 745 * A callback for unicode errors in D. A $(LREF UnicodeException) will be thrown. 746 * 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. 752 * 753 * Throws: 754 * $(LREF UnicodeException). 755 */ 756 extern (C) noreturn onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure 757 { 758 throw new UnicodeException( msg, idx, file, line ); 759 } 760 761 /*********************************** 762 * These functions must be defined for any D program linked 763 * against this library. 764 */ 765 /+ 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); 771 +/ 772 773 /*********************************** 774 * Function calls to these are generated by the compiler and inserted into 775 * the object code. 776 */ 777 778 extern (C) 779 { 780 /* One of these three is called upon an assert() fail. 781 */ 782 void _d_assertp(immutable(char)* file, uint line) 783 { 784 import core.stdc.string : strlen; 785 onAssertError(file[0 .. strlen(file)], line); 786 } 787 788 void _d_assert_msg(string msg, string file, uint line) 789 { 790 onAssertErrorMsg(file, line, msg); 791 } 792 793 void _d_assert(string file, uint line) 794 { 795 onAssertError(file, line); 796 } 797 798 /* One of these three is called upon an assert() fail inside of a unittest block 799 */ 800 void _d_unittestp(immutable(char)* file, uint line) 801 { 802 import core.stdc.string : strlen; 803 _d_unittest(file[0 .. strlen(file)], line); 804 } 805 806 void _d_unittest_msg(string msg, string file, uint line) 807 { 808 onUnittestErrorMsg(file, line, msg); 809 } 810 811 void _d_unittest(string file, uint line) 812 { 813 _d_unittest_msg("unittest failure", file, line); 814 } 815 816 /// Called when an invalid array index/slice or associative array key is accessed 817 void _d_arrayboundsp(immutable(char*) file, uint line) 818 { 819 import core.stdc.string : strlen; 820 onRangeError(file[0 .. strlen(file)], line); 821 } 822 823 /// ditto 824 void _d_arraybounds(string file, uint line) 825 { 826 onRangeError(file, line); 827 } 828 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) 831 { 832 import core.stdc.string : strlen; 833 onArraySliceError(lower, upper, length, file[0 .. strlen(file)], line); 834 } 835 836 /// ditto 837 void _d_arraybounds_slice(string file, uint line, size_t lower, size_t upper, size_t length) 838 { 839 onArraySliceError(lower, upper, length, file, line); 840 } 841 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) 844 { 845 import core.stdc.string : strlen; 846 onArrayIndexError(index, length, file[0 .. strlen(file)], line); 847 } 848 849 /// ditto 850 void _d_arraybounds_index(string file, uint line, size_t index, size_t length) 851 { 852 onArrayIndexError(index, length, file, line); 853 } 854 } 855 856 // TLS storage shared for all errors, chaining might create circular reference 857 private align(2 * size_t.sizeof) void[256] _store; 858 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)) 862 { 863 // pure hack, what we actually need is @noreturn and allow to call that in pure functions 864 static T get() 865 { 866 static assert(__traits(classInstanceSize, T) <= _store.length, 867 T.stringof ~ " is too large for staticError()"); 868 869 return cast(T) _store.ptr; 870 } 871 auto res = (cast(T function() @trusted pure nothrow @nogc) &get)(); 872 import core.lifetime : emplace; 873 emplace(res, args); 874 return res; 875 } 876 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 880 { 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 885 { 886 static immutable SuppressTraceInfo it = new SuppressTraceInfo; 887 return cast(SuppressTraceInfo)it; 888 } 889 }