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 }