diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2019-06-18 20:42:10 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-11-30 16:53:28 +0100 |
commit | 5fee5ec362f7a243f459e6378fd49dfc89dc9fb5 (patch) | |
tree | 61d1bdbca854a903c0860406f457f06b2040be7a /libphobos/src/std/exception.d | |
parent | b3f60112edcb85b459e60f66c44a55138b1cef49 (diff) | |
download | gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.zip gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.gz gcc-5fee5ec362f7a243f459e6378fd49dfc89dc9fb5.tar.bz2 |
d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
The D front-end is now itself written in D, in order to build GDC, you
will need a working GDC compiler (GCC version 9.1 or later).
GCC changes:
- Add support for bootstrapping the D front-end.
These add the required components in order to have a D front-end written
in D itself. Because the compiler front-end only depends on the core
runtime modules, only libdruntime is built for the bootstrap stages.
D front-end changes:
- Import dmd v2.098.0-beta.1.
Druntime changes:
- Import druntime v2.098.0-beta.1.
Phobos changes:
- Import phobos v2.098.0-beta.1.
The jump from v2.076.1 to v2.098.0 covers nearly 4 years worth of
development on the D programming language and run-time libraries.
ChangeLog:
* Makefile.def: Add bootstrap to libbacktrace, libphobos, zlib, and
libatomic.
* Makefile.in: Regenerate.
* Makefile.tpl (POSTSTAGE1_HOST_EXPORTS): Fix command for GDC.
(STAGE1_CONFIGURE_FLAGS): Add --with-libphobos-druntime-only if
target-libphobos-bootstrap.
(STAGE2_CONFIGURE_FLAGS): Likewise.
* configure: Regenerate.
* configure.ac: Add support for bootstrapping D front-end.
config/ChangeLog:
* acx.m4 (ACX_PROG_GDC): New m4 function.
gcc/ChangeLog:
* Makefile.in (GDC): New variable.
(GDCFLAGS): New variable.
* configure: Regenerate.
* configure.ac: Add call to ACX_PROG_GDC. Substitute GDCFLAGS.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd b8384668f.
* Make-lang.in (d-warn): Use strict warnings.
(DMD_WARN_CXXFLAGS): Remove.
(DMD_COMPILE): Remove.
(CHECKING_DFLAGS): Define.
(WARN_DFLAGS): Define.
(ALL_DFLAGS): Define.
(DCOMPILE.base): Define.
(DCOMPILE): Define.
(DPOSTCOMPILE): Define.
(DLINKER): Define.
(DLLINKER): Define.
(D_FRONTEND_OBJS): Add new dmd front-end objects.
(D_GENERATED_SRCS): Remove.
(D_GENERATED_OBJS): Remove.
(D_ALL_OBJS): Remove D_GENERATED_OBJS.
(d21$(exeext)): Build using DLLINKER and -static-libphobos.
(d.tags): Remove dmd/*.c and dmd/root/*.c.
(d.mostlyclean): Remove D_GENERATED_SRCS, d/idgen$(build_exeext),
d/impcnvgen$(build_exeext).
(D_INCLUDES): Include $(srcdir)/d/dmd/res.
(CFLAGS-d/id.o): Remove.
(CFLAGS-d/impcnvtab.o): Remove.
(d/%.o): Build using DCOMPILE and DPOSTCOMPILE. Update dependencies
from d/dmd/%.c to d/dmd/%.d.
(d/idgen$(build_exeext)): Remove.
(d/impcnvgen$(build_exeext)): Remove.
(d/id.c): Remove.
(d/id.h): Remove.
(d/impcnvtab.c): Remove.
(d/%.dmdgen.o): Remove.
(D_SYSTEM_H): Remove.
(d/idgen.dmdgen.o): Remove.
(d/impcnvgen.dmdgen.o): Remove.
* config-lang.in (boot_language): New variable.
* d-attribs.cc: Include dmd/expression.h.
* d-builtins.cc: Include d-frontend.h.
(build_frontend_type): Update for new front-end interface.
(d_eval_constant_expression): Likewise.
(d_build_builtins_module): Likewise.
(maybe_set_builtin_1): Likewise.
(d_build_d_type_nodes): Likewise.
* d-codegen.cc (d_decl_context): Likewise.
(declaration_reference_p): Likewise.
(declaration_type): Likewise.
(parameter_reference_p): Likewise.
(parameter_type): Likewise.
(get_array_length): Likewise.
(build_delegate_cst): Likewise.
(build_typeof_null_value): Likewise.
(identity_compare_p): Likewise.
(lower_struct_comparison): Likewise.
(build_filename_from_loc): Likewise.
(build_assert_call): Remove LIBCALL_SWITCH_ERROR.
(build_bounds_index_condition): Call LIBCALL_ARRAYBOUNDS_INDEXP on
bounds error.
(build_bounds_slice_condition): Call LIBCALL_ARRAYBOUNDS_SLICEP on
bounds error.
(array_bounds_check): Update for new front-end interface.
(checkaction_trap_p): Handle CHECKACTION_context.
(get_function_type): Update for new front-end interface.
(d_build_call): Likewise.
* d-compiler.cc: Remove include of dmd/scope.h.
(Compiler::genCmain): Remove.
(Compiler::paintAsType): Update for new front-end interface.
(Compiler::onParseModule): Likewise.
* d-convert.cc (convert_expr): Remove call to LIBCALL_ARRAYCAST.
(convert_for_rvalue): Update for new front-end interface.
(convert_for_assignment): Likewise.
(convert_for_condition): Likewise.
(d_array_convert): Likewise.
* d-diagnostic.cc (error): Remove.
(errorSupplemental): Remove.
(warning): Remove.
(warningSupplemental): Remove.
(deprecation): Remove.
(deprecationSupplemental): Remove.
(message): Remove.
(vtip): New.
* d-frontend.cc (global): Remove.
(Global::_init): Remove.
(Global::startGagging): Remove.
(Global::endGagging): Remove.
(Global::increaseErrorCount): Remove.
(Loc::Loc): Remove.
(Loc::toChars): Remove.
(Loc::equals): Remove.
(isBuiltin): Update for new front-end interface.
(eval_builtin): Likewise.
(getTypeInfoType): Likewise.
(inlineCopy): Remove.
* d-incpath.cc: Include d-frontend.h.
(add_globalpaths): Call d_gc_malloc to allocate Strings.
(add_filepaths): Likewise.
* d-lang.cc: Include dmd/id.h, dmd/root/file.h, d-frontend.h. Remove
include of dmd/mars.h, id.h.
(entrypoint_module): Remove.
(entrypoint_root_module): Remove.
(deps_write_string): Update for new front-end interface.
(deps_write): Likewise.
(d_init_options): Call rt_init. Remove setting global params that are
default initialized by the front-end.
(d_handle_option): Handle OPT_fcheckaction_, OPT_fdump_c___spec_,
OPT_fdump_c___spec_verbose, OPT_fextern_std_, OPT_fpreview,
OPT_revert, OPT_fsave_mixins_, and OPT_ftransition.
(d_post_options): Propagate dip1021 and dip1000 preview flags to
dip25, and flag_diagnostics_show_caret to printErrorContext.
(d_add_entrypoint_module): Remove.
(d_parse_file): Update for new front-end interface.
(d_type_promotes_to): Likewise.
(d_types_compatible_p): Likewise.
* d-longdouble.cc (CTFloat::zero): Remove.
(CTFloat::one): Remove.
(CTFloat::minusone): Remove.
(CTFloat::half): Remove.
* d-system.h (POSIX): Remove.
(realpath): Remove.
(isalpha): Remove.
(isalnum): Remove.
(isdigit): Remove.
(islower): Remove.
(isprint): Remove.
(isspace): Remove.
(isupper): Remove.
(isxdigit): Remove.
(tolower): Remove.
(_mkdir): Remove.
(INT32_MAX): Remove.
(INT32_MIN): Remove.
(INT64_MIN): Remove.
(UINT32_MAX): Remove.
(UINT64_MAX): Remove.
* d-target.cc: Include calls.h.
(target): Remove.
(define_float_constants): Remove initialization of snan.
(Target::_init): Update for new front-end interface.
(Target::isVectorTypeSupported): Likewise.
(Target::isVectorOpSupported): Remove cases for unordered operators.
(TargetCPP::typeMangle): Update for new front-end interface.
(TargetCPP::parameterType): Likewise.
(Target::systemLinkage): Likewise.
(Target::isReturnOnStack): Likewise.
(Target::isCalleeDestroyingArgs): Define.
(Target::preferPassByRef): Define.
* d-tree.h (d_add_entrypoint_module): Remove.
* decl.cc (gcc_attribute_p): Update for new front-end interface.
(apply_pragma_crt): Define.
(DeclVisitor::visit(PragmaDeclaration *)): Handle pragmas
crt_constructor and crt_destructor.
(DeclVisitor::visit(TemplateDeclaration *)): Update for new front-end
interface.
(DeclVisitor::visit): Likewise.
(DeclVisitor::finish_vtable): Likewise.
(get_symbol_decl): Error if template has more than one nesting
context. Update for new front-end interface.
(make_thunk): Update for new front-end interface.
(get_vtable_decl): Likewise.
* expr.cc (ExprVisitor::visit): Likewise.
(build_return_dtor): Likewise.
* imports.cc (ImportVisitor::visit): Likewise.
* intrinsics.cc: Include dmd/expression.h. Remove include of
dmd/mangle.h.
(maybe_set_intrinsic): Update for new front-end interface.
* intrinsics.def (INTRINSIC_ROL): Update intrinsic signature.
(INTRINSIC_ROR): Likewise.
(INTRINSIC_ROR_TIARG): Likewise.
(INTRINSIC_TOPREC): Likewise.
(INTRINSIC_TOPRECL): Likewise.
(INTRINSIC_TAN): Update intrinsic module and signature.
(INTRINSIC_ISNAN): Likewise.
(INTRINSIC_ISFINITE): Likewise.
(INTRINSIC_COPYSIGN): Define intrinsic.
(INTRINSIC_COPYSIGNI): Define intrinsic.
(INTRINSIC_EXP): Update intrinsic module.
(INTRINSIC_EXPM1): Likewise.
(INTRINSIC_EXP2): Likewise.
(INTRINSIC_LOG): Likewise.
(INTRINSIC_LOG2): Likewise.
(INTRINSIC_LOG10): Likewise.
(INTRINSIC_POW): Likewise.
(INTRINSIC_ROUND): Likewise.
(INTRINSIC_FLOORF): Likewise.
(INTRINSIC_FLOOR): Likewise.
(INTRINSIC_FLOORL): Likewise.
(INTRINSIC_CEILF): Likewise.
(INTRINSIC_CEIL): Likewise.
(INTRINSIC_CEILL): Likewise.
(INTRINSIC_TRUNC): Likewise.
(INTRINSIC_FMIN): Likewise.
(INTRINSIC_FMAX): Likewise.
(INTRINSIC_FMA): Likewise.
(INTRINSIC_VA_ARG): Update intrinsic signature.
(INTRINSIC_VASTART): Likewise.
* lang.opt (fcheck=): Add alternate aliases for contract switches.
(fcheckaction=): New option.
(check_action): New Enum and EnumValue entries.
(fdump-c++-spec-verbose): New option.
(fdump-c++-spec=): New option.
(fextern-std=): New option.
(extern_stdcpp): New Enum and EnumValue entries
(fpreview=): New options.
(frevert=): New options.
(fsave-mixins): New option.
(ftransition=): Update options.
* modules.cc (get_internal_fn): Replace Prot with Visibility.
(build_internal_fn): Likewise.
(build_dso_cdtor_fn): Likewise.
(build_module_tree): Remove check for __entrypoint module.
* runtime.def (P5): Define.
(ARRAYBOUNDS_SLICEP): Define.
(ARRAYBOUNDS_INDEXP): Define.
(NEWTHROW): Define.
(ADCMP2): Remove.
(ARRAYCAST): Remove.
(SWITCH_STRING): Remove.
(SWITCH_USTRING): Remove.
(SWITCH_DSTRING): Remove.
(SWITCH_ERROR): Remove.
* toir.cc (IRVisitor::visit): Update for new front-end interface.
(IRVisitor::check_previous_goto): Remove checks for case and default
statements.
(IRVisitor::visit(SwitchStatement *)): Remove handling of string
switch conditions.
* typeinfo.cc: Include d-frontend.h.
(get_typeinfo_kind): Update for new front-end interface.
(make_frontend_typeinfo): Likewise.
(TypeInfoVisitor::visit): Likewise.
(builtin_typeinfo_p): Likewise.
(get_typeinfo_decl): Likewise.
(build_typeinfo): Likewise.
* types.cc (valist_array_p): Likewise.
(make_array_type): Likewise.
(merge_aggregate_types): Likewise.
(TypeVisitor::visit(TypeBasic *)): Likewise.
(TypeVisitor::visit(TypeFunction *)): Likewise.
(TypeVisitor::visit(TypeStruct *)): Update comment.
* verstr.h: Removed.
* d-frontend.h: New file.
gcc/po/ChangeLog:
* EXCLUDES: Remove d/dmd sources from list.
gcc/testsuite/ChangeLog:
* gdc.dg/Wcastresult2.d: Update test.
* gdc.dg/asm1.d: Likewise.
* gdc.dg/asm2.d: Likewise.
* gdc.dg/asm3.d: Likewise.
* gdc.dg/gdc282.d: Likewise.
* gdc.dg/imports/gdc170.d: Likewise.
* gdc.dg/intrinsics.d: Likewise.
* gdc.dg/pr101672.d: Likewise.
* gdc.dg/pr90650a.d: Likewise.
* gdc.dg/pr90650b.d: Likewise.
* gdc.dg/pr94777a.d: Likewise.
* gdc.dg/pr95250.d: Likewise.
* gdc.dg/pr96869.d: Likewise.
* gdc.dg/pr98277.d: Likewise.
* gdc.dg/pr98457.d: Likewise.
* gdc.dg/simd1.d: Likewise.
* gdc.dg/simd2a.d: Likewise.
* gdc.dg/simd2b.d: Likewise.
* gdc.dg/simd2c.d: Likewise.
* gdc.dg/simd2d.d: Likewise.
* gdc.dg/simd2e.d: Likewise.
* gdc.dg/simd2f.d: Likewise.
* gdc.dg/simd2g.d: Likewise.
* gdc.dg/simd2h.d: Likewise.
* gdc.dg/simd2i.d: Likewise.
* gdc.dg/simd2j.d: Likewise.
* gdc.dg/simd7951.d: Likewise.
* gdc.dg/torture/gdc309.d: Likewise.
* gdc.dg/torture/pr94424.d: Likewise.
* gdc.dg/torture/pr94777b.d: Likewise.
* lib/gdc-utils.exp (gdc-convert-args): Handle new compiler options.
(gdc-convert-test): Handle CXXFLAGS, EXTRA_OBJC_SOURCES, and ARG_SETS
test directives.
(gdc-do-test): Only import modules in the test run directory.
* gdc.dg/pr94777c.d: New test.
* gdc.dg/pr96156b.d: New test.
* gdc.dg/pr96157c.d: New test.
* gdc.dg/simd_ctfe.d: New test.
* gdc.dg/torture/simd17344.d: New test.
* gdc.dg/torture/simd20052.d: New test.
* gdc.dg/torture/simd6.d: New test.
* gdc.dg/torture/simd7.d: New test.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime e6caaab9.
* libdruntime/Makefile.am (D_EXTRA_FLAGS): Build libdruntime with
-fpreview=dip1000, -fpreview=fieldwise, and -fpreview=dtorfields.
(ALL_DRUNTIME_SOURCES): Add DRUNTIME_DSOURCES_STDCXX.
(DRUNTIME_DSOURCES): Update list of C binding modules.
(DRUNTIME_DSOURCES_STDCXX): Likewise.
(DRUNTIME_DSOURCES_LINUX): Likewise.
(DRUNTIME_DSOURCES_OPENBSD): Likewise.
(DRUNTIME_DISOURCES): Remove __entrypoint.di.
* libdruntime/Makefile.in: Regenerated.
* libdruntime/__entrypoint.di: Removed.
* libdruntime/gcc/deh.d (_d_isbaseof): Update signature.
(_d_createTrace): Likewise.
(__gdc_begin_catch): Remove reference to the exception.
(_d_throw): Increment reference count of thrown object before unwind.
(__gdc_personality): Chain exceptions with Throwable.chainTogether.
* libdruntime/gcc/emutls.d: Update imports.
* libdruntime/gcc/sections/elf.d: Update imports.
(DSO.moduleGroup): Update signature.
* libdruntime/gcc/sections/macho.d: Update imports.
(DSO.moduleGroup): Update signature.
* libdruntime/gcc/sections/pecoff.d: Update imports.
(DSO.moduleGroup): Update signature.
* src/MERGE: Merge upstream phobos 5ab9ad256.
* src/Makefile.am (D_EXTRA_DFLAGS): Add -fpreview=dip1000 and
-fpreview=dtorfields flags.
(PHOBOS_DSOURCES): Update list of std modules.
* src/Makefile.in: Regenerate.
* testsuite/lib/libphobos.exp (libphobos-dg-test): Handle assembly
compile types.
(dg-test): Override.
(additional_prunes): Define.
(libphobos-dg-prune): Filter any additional_prunes set by tests.
* testsuite/libphobos.aa/test_aa.d: Update test.
* testsuite/libphobos.druntime/druntime.exp (version_flags): Add
-fversion=CoreUnittest.
* testsuite/libphobos.druntime_shared/druntime_shared.exp
(version_flags): Add -fversion=CoreUnittest -fversion=Shared.
* testsuite/libphobos.exceptions/unknown_gc.d: Update test.
* testsuite/libphobos.hash/test_hash.d: Update test.
* testsuite/libphobos.phobos/phobos.exp (version_flags): Add
-fversion=StdUnittest
* testsuite/libphobos.phobos_shared/phobos_shared.exp (version_flags):
Likewise.
* testsuite/libphobos.shared/host.c: Update test.
* testsuite/libphobos.shared/load.d: Update test.
* testsuite/libphobos.shared/load_13414.d: Update test.
* testsuite/libphobos.thread/fiber_guard_page.d: Update test.
* testsuite/libphobos.thread/tlsgc_sections.d: Update test.
* testsuite/testsuite_flags.in: Add -fpreview=dip1000 to --gdcflags.
* testsuite/libphobos.shared/link_mod_collision.d: Removed.
* testsuite/libphobos.shared/load_mod_collision.d: Removed.
* testsuite/libphobos.betterc/betterc.exp: New test.
* testsuite/libphobos.config/config.exp: New test.
* testsuite/libphobos.gc/gc.exp: New test.
* testsuite/libphobos.imports/imports.exp: New test.
* testsuite/libphobos.lifetime/lifetime.exp: New test.
* testsuite/libphobos.unittest/unittest.exp: New test.
Diffstat (limited to 'libphobos/src/std/exception.d')
-rw-r--r-- | libphobos/src/std/exception.d | 920 |
1 files changed, 529 insertions, 391 deletions
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d index 56133c9..5fcee2a 100644 --- a/libphobos/src/std/exception.d +++ b/libphobos/src/std/exception.d @@ -5,6 +5,7 @@ handling. It also defines functions intended to aid in unit testing. $(SCRIPT inhibitQuickIndex = 1;) +$(DIVC quickindex, $(BOOKTABLE, $(TR $(TH Category) $(TH Functions)) $(TR $(TD Assumptions) $(TD @@ -17,7 +18,6 @@ $(TR $(TD Assumptions) $(TD $(TR $(TD Enforce) $(TD $(LREF doesPointTo) $(LREF enforce) - $(LREF enforceEx) $(LREF errnoEnforce) )) $(TR $(TD Handlers) $(TD @@ -32,68 +32,107 @@ $(TR $(TD Other) $(TD $(LREF ErrnoException) $(LREF RangePrimitive) )) -) +)) - Synopsis of some of std.exception's functions: - -------------------- - string synopsis() - { - FILE* f = enforce(fopen("some/file")); - // f is not null from here on - FILE* g = enforce!WriteException(fopen("some/other/file", "w")); - // g is not null from here on + Copyright: Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-. + License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) + Authors: $(HTTP erdani.org, Andrei Alexandrescu) and + $(HTTP jmdavisprog.com, Jonathan M Davis) + Source: $(PHOBOSSRC std/exception.d) - Exception e = collectException(write(g, readln(f))); - if (e) - { - ... an exception occurred... - ... We have the exception to play around with... - } + +/ +module std.exception; - string msg = collectExceptionMsg(write(g, readln(f))); - if (msg) - { - ... an exception occurred... - ... We have the message from the exception but not the exception... - } +/// Synopis +@system unittest +{ + import core.stdc.stdlib : malloc, free; + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.algorithm.searching : endsWith; + import std.conv : ConvException, to; + import std.range : front, retro; + + // use enforce like assert + int a = 3; + enforce(a > 2, "a needs to be higher than 2."); + + // enforce can throw a custom exception + enforce!ConvException(a > 2, "a needs to be higher than 2."); + + // enforce will return it's input + enum size = 42; + auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; + scope(exit) free(memory.ptr); + + // collectException can be used to test for exceptions + Exception e = collectException("abc".to!int); + assert(e.file.endsWith("conv.d")); + + // and just for the exception message + string msg = collectExceptionMsg("abc".to!int); + assert(msg == "Unexpected 'a' when converting from type string to type int"); + + // assertThrown can be used to assert that an exception is thrown + assertThrown!ConvException("abc".to!int); - char[] line; - enforce(readln(f, line)); - return assumeUnique(line); + // ifThrown can be used to provide a default value if an exception is thrown + assert("x".to!int().ifThrown(0) == 0); + + // handle is a more advanced version of ifThrown for ranges + auto r = "12,1337z32,54".splitter(',').map!(a => to!int(a)); + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54])); + assertThrown!ConvException(h.retro.equal([54, 0, 12])); + + // basicExceptionCtors avoids the boilerplate when creating custom exceptions + static class MeaCulpa : Exception + { + mixin basicExceptionCtors; } - -------------------- + e = collectException((){throw new MeaCulpa("diagnostic message");}()); + assert(e.msg == "diagnostic message"); + assert(e.file == __FILE__); + assert(e.line == __LINE__ - 3); - Copyright: Copyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-. - License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0) - Authors: $(HTTP erdani.org, Andrei Alexandrescu) and Jonathan M Davis - Source: $(PHOBOSSRC std/_exception.d) + // assumeWontThrow can be used to cast throwing code into `nothrow` + void exceptionFreeCode() nothrow + { + // auto-decoding only throws if an invalid UTF char is given + assumeWontThrow("abc".front); + } - +/ -module std.exception; + // assumeUnique can be used to cast mutable instance to an `immutable` one + // use with care + char[] str = " mutable".dup; + str[0 .. 2] = "im"; + immutable res = assumeUnique(str); + assert(res == "immutable"); +} import std.range.primitives; import std.traits; /++ Asserts that the given expression does $(I not) throw the given type - of $(D Throwable). If a $(D Throwable) of the given type is thrown, + of `Throwable`. If a `Throwable` of the given type is thrown, it is caught and does not escape assertNotThrown. Rather, an - $(D AssertError) is thrown. However, any other $(D Throwable)s will escape. + `AssertError` is thrown. However, any other `Throwable`s will escape. Params: - T = The $(D Throwable) to test for. + T = The `Throwable` to test for. expression = The expression to test. msg = Optional message to output on test failure. If msg is empty, and the thrown exception has a non-empty msg field, the exception's msg field will be output on test failure. file = The file where the error occurred. - Defaults to $(D __FILE__). + Defaults to `__FILE__`. line = The line where the error occurred. - Defaults to $(D __LINE__). + Defaults to `__LINE__`. Throws: - $(D AssertError) if the given $(D Throwable) is thrown. + `AssertError` if the given `Throwable` is thrown. Returns: the result of `expression`. @@ -226,22 +265,22 @@ auto assertNotThrown(T : Throwable = Exception, E) } /++ - Asserts that the given expression throws the given type of $(D Throwable). - The $(D Throwable) is caught and does not escape assertThrown. However, - any other $(D Throwable)s $(I will) escape, and if no $(D Throwable) - of the given type is thrown, then an $(D AssertError) is thrown. + Asserts that the given expression throws the given type of `Throwable`. + The `Throwable` is caught and does not escape assertThrown. However, + any other `Throwable`s $(I will) escape, and if no `Throwable` + of the given type is thrown, then an `AssertError` is thrown. Params: - T = The $(D Throwable) to test for. + T = The `Throwable` to test for. expression = The expression to test. msg = Optional message to output on test failure. file = The file where the error occurred. - Defaults to $(D __FILE__). + Defaults to `__FILE__`. line = The line where the error occurred. - Defaults to $(D __LINE__). + Defaults to `__LINE__`. Throws: - $(D AssertError) if the given $(D Throwable) is not thrown. + `AssertError` if the given `Throwable` is not thrown. +/ void assertThrown(T : Throwable = Exception, E) (lazy E expression, @@ -355,55 +394,52 @@ void assertThrown(T : Throwable = Exception, E) /++ Enforces that the given value is true. + If the given value is false, an exception is thrown. + The + $(UL + $(LI `msg` - error message as a `string`) + $(LI `dg` - custom delegate that return a string and is only called if an exception occurred) + $(LI `ex` - custom exception to be thrown. It is `lazy` and is only created if an exception occurred) + ) Params: value = The value to test. - E = Exception type to throw if the value evalues to false. + E = Exception type to throw if the value evaluates to false. msg = The error message to put in the exception if it is thrown. + dg = The delegate to be called if the value evaluates to false. + ex = The exception to throw if the value evaluates to false. file = The source file of the caller. line = The line number of the caller. - Returns: $(D value), if `cast(bool) value` is true. Otherwise, - $(D new Exception(msg)) is thrown. + Returns: `value`, if `cast(bool) value` is true. Otherwise, + depending on the chosen overload, `new Exception(msg)`, `dg()` or `ex` is thrown. Note: - $(D enforce) is used to throw exceptions and is therefore intended to + `enforce` is used to throw exceptions and is therefore intended to aid in error handling. It is $(I not) intended for verifying the logic - of your program. That is what $(D assert) is for. Also, do not use - $(D enforce) inside of contracts (i.e. inside of $(D in) and $(D out) - blocks and $(D invariant)s), because they will be compiled out when - compiling with $(I -release). Use $(D assert) in contracts. - - Example: - -------------------- - auto f = enforce(fopen("data.txt")); - auto line = readln(f); - enforce(line.length, "Expected a non-empty line."); - -------------------- + of your program. That is what `assert` is for. Also, do not use + `enforce` inside of contracts (i.e. inside of `in` and `out` + blocks and `invariant`s), because contracts are compiled out when + compiling with $(I -release). + + If a delegate is passed, the safety and purity of this function are inferred + from `Dg`'s safety and purity. +/ -T enforce(E : Throwable = Exception, T)(T value, lazy const(char)[] msg = null, -string file = __FILE__, size_t line = __LINE__) -if (is(typeof({ if (!value) {} }))) +template enforce(E : Throwable = Exception) +if (is(typeof(new E("", string.init, size_t.init)) : Throwable) || + is(typeof(new E(string.init, size_t.init)) : Throwable)) { - if (!value) bailOut!E(file, line, msg); - return value; + /// + T enforce(T)(T value, lazy const(char)[] msg = null, + string file = __FILE__, size_t line = __LINE__) + if (is(typeof({ if (!value) {} }))) + { + if (!value) bailOut!E(file, line, msg); + return value; + } } -/++ - Enforces that the given value is true. - - Params: - value = The value to test. - dg = The delegate to be called if the value evaluates to false. - file = The source file of the caller. - line = The line number of the caller. - - Returns: $(D value), if `cast(bool) value` is true. Otherwise, the given - delegate is called. - - The safety and purity of this function are inferred from $(D Dg)'s safety - and purity. - +/ +/// ditto T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__) (T value, scope Dg dg) if (isSomeFunction!Dg && is(typeof( dg() )) && @@ -413,23 +449,40 @@ if (isSomeFunction!Dg && is(typeof( dg() )) && return value; } -private void bailOut(E : Throwable = Exception)(string file, size_t line, in char[] msg) +/// ditto +T enforce(T)(T value, lazy Throwable ex) { - static if (is(typeof(new E(string.init, string.init, size_t.init)))) - { - throw new E(msg ? msg.idup : "Enforcement failed", file, line); - } - else static if (is(typeof(new E(string.init, size_t.init)))) - { - throw new E(file, line); - } - else - { - static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~ - " constructor for " ~ __traits(identifier, E)); - } + if (!value) throw ex(); + return value; +} + +/// +@system unittest +{ + import core.stdc.stdlib : malloc, free; + import std.conv : ConvException, to; + + // use enforce like assert + int a = 3; + enforce(a > 2, "a needs to be higher than 2."); + + // enforce can throw a custom exception + enforce!ConvException(a > 2, "a needs to be higher than 2."); + + // enforce will return it's input + enum size = 42; + auto memory = enforce(malloc(size), "malloc failed")[0 .. size]; + scope(exit) free(memory.ptr); +} + +/// +@safe unittest +{ + assertNotThrown(enforce(true, new Exception("this should not be thrown"))); + assertThrown(enforce(false, new Exception("this should be thrown"))); } +/// @safe unittest { assert(enforce(123) == 123); @@ -447,9 +500,35 @@ private void bailOut(E : Throwable = Exception)(string file, size_t line, in cha } } +/// Alias your own enforce function +@safe unittest +{ + import std.conv : ConvException; + alias convEnforce = enforce!ConvException; + assertNotThrown(convEnforce(true)); + assertThrown!ConvException(convEnforce(false, "blah")); +} + +private noreturn bailOut(E : Throwable = Exception)(string file, size_t line, scope const(char)[] msg) +{ + static if (is(typeof(new E(string.init, string.init, size_t.init)))) + { + throw new E(msg ? msg.idup : "Enforcement failed", file, line); + } + else static if (is(typeof(new E(string.init, size_t.init)))) + { + throw new E(file, line); + } + else + { + static assert(0, "Expected this(string, string, size_t) or this(string, size_t)" ~ + " constructor for " ~ __traits(identifier, E)); + } +} + +// https://issues.dlang.org/show_bug.cgi?id=10510 @safe unittest { - // Issue 10510 extern(C) void cFoo() { } enforce(false, &cFoo); } @@ -457,14 +536,12 @@ private void bailOut(E : Throwable = Exception)(string file, size_t line, in cha // purity and safety inference test @system unittest { - import std.meta : AliasSeq; - - foreach (EncloseSafe; AliasSeq!(false, true)) - foreach (EnclosePure; AliasSeq!(false, true)) + static foreach (EncloseSafe; [false, true]) + static foreach (EnclosePure; [false, true]) { - foreach (BodySafe; AliasSeq!(false, true)) - foreach (BodyPure; AliasSeq!(false, true)) - { + static foreach (BodySafe; [false, true]) + static foreach (BodyPure; [false, true]) + {{ enum code = "delegate void() " ~ (EncloseSafe ? "@safe " : "") ~ @@ -485,11 +562,11 @@ private void bailOut(E : Throwable = Exception)(string file, size_t line, in cha "code = ", code); static assert(__traits(compiles, mixin(code)()) == expect); - } + }} } } -// Test for bugzilla 8637 +// Test for https://issues.dlang.org/show_bug.cgi?id=8637 @system unittest { struct S @@ -523,10 +600,9 @@ private void bailOut(E : Throwable = Exception)(string file, size_t line, in cha enforce!E2(s); } +// https://issues.dlang.org/show_bug.cgi?id=14685 @safe unittest { - // Issue 14685 - class E : Exception { this() { super("Not found"); } @@ -535,35 +611,6 @@ private void bailOut(E : Throwable = Exception)(string file, size_t line, in cha } /++ - Enforces that the given value is true. - - Params: - value = The value to test. - ex = The exception to throw if the value evaluates to false. - - Returns: $(D value), if `cast(bool) value` is true. Otherwise, $(D ex) is - thrown. - - Example: - -------------------- - auto f = enforce(fopen("data.txt")); - auto line = readln(f); - enforce(line.length, new IOException); // expect a non-empty line - -------------------- - +/ -T enforce(T)(T value, lazy Throwable ex) -{ - if (!value) throw ex(); - return value; -} - -@safe unittest -{ - assertNotThrown(enforce(true, new Exception("this should not be thrown"))); - assertThrown(enforce(false, new Exception("this should be thrown"))); -} - -/++ Enforces that the given value is true, throwing an `ErrnoException` if it is not. @@ -571,125 +618,37 @@ T enforce(T)(T value, lazy Throwable ex) value = The value to test. msg = The message to include in the `ErrnoException` if it is thrown. - Returns: $(D value), if `cast(bool) value` is true. Otherwise, + Returns: `value`, if `cast(bool) value` is true. Otherwise, $(D new ErrnoException(msg)) is thrown. It is assumed that the last - operation set $(D errno) to an error code corresponding with the failed + operation set `errno` to an error code corresponding with the failed condition. - - Example: - -------------------- - auto f = errnoEnforce(fopen("data.txt")); - auto line = readln(f); - enforce(line.length); // expect a non-empty line - -------------------- - +/ -T errnoEnforce(T, string file = __FILE__, size_t line = __LINE__) - (T value, lazy string msg = null) -{ - if (!value) throw new ErrnoException(msg, file, line); - return value; -} - - -/++ - If $(D !value) is $(D false), $(D value) is returned. Otherwise, - $(D new E(msg, file, line)) is thrown. Or if $(D E) doesn't take a message - and can be constructed with $(D new E(file, line)), then - $(D new E(file, line)) will be thrown. - - This is legacy name, it is recommended to use $(D enforce!E) instead. - - Example: - -------------------- - auto f = enforceEx!FileMissingException(fopen("data.txt")); - auto line = readln(f); - enforceEx!DataCorruptionException(line.length); - -------------------- +/ -template enforceEx(E : Throwable) -if (is(typeof(new E("", __FILE__, __LINE__)))) -{ - /++ Ditto +/ - T enforceEx(T)(T value, lazy string msg = "", string file = __FILE__, size_t line = __LINE__) - { - if (!value) throw new E(msg, file, line); - return value; - } -} - -/++ Ditto +/ -template enforceEx(E : Throwable) -if (is(typeof(new E(__FILE__, __LINE__))) && !is(typeof(new E("", __FILE__, __LINE__)))) -{ - /++ Ditto +/ - T enforceEx(T)(T value, string file = __FILE__, size_t line = __LINE__) - { - if (!value) throw new E(file, line); - return value; - } -} +alias errnoEnforce = enforce!ErrnoException; +/// @system unittest { - import core.exception : OutOfMemoryError; - import std.array : empty; - assertNotThrown(enforceEx!Exception(true)); - assertNotThrown(enforceEx!Exception(true, "blah")); - assertNotThrown(enforceEx!OutOfMemoryError(true)); - - { - auto e = collectException(enforceEx!Exception(false)); - assert(e !is null); - assert(e.msg.empty); - assert(e.file == __FILE__); - assert(e.line == __LINE__ - 4); - } + import core.stdc.stdio : fclose, fgets, fopen; + import std.file : thisExePath; + import std.string : toStringz; - { - auto e = collectException(enforceEx!Exception(false, "hello", "file", 42)); - assert(e !is null); - assert(e.msg == "hello"); - assert(e.file == "file"); - assert(e.line == 42); - } - - { - auto e = collectException!Error(enforceEx!OutOfMemoryError(false)); - assert(e !is null); - assert(e.msg == "Memory allocation failed"); - assert(e.file == __FILE__); - assert(e.line == __LINE__ - 4); - } - - { - auto e = collectException!Error(enforceEx!OutOfMemoryError(false, "file", 42)); - assert(e !is null); - assert(e.msg == "Memory allocation failed"); - assert(e.file == "file"); - assert(e.line == 42); - } - - static assert(!is(typeof(enforceEx!int(true)))); + auto f = fopen(thisExePath.toStringz, "r").errnoEnforce; + scope(exit) fclose(f); + char[100] buf; + auto line = fgets(buf.ptr, buf.length, f); + enforce(line !is null); // expect a non-empty line } -@safe unittest -{ - alias enf = enforceEx!Exception; - assertNotThrown(enf(true)); - assertThrown(enf(false, "blah")); -} - - /++ Catches and returns the exception thrown from the given expression. - If no exception is thrown, then null is returned and $(D result) is + If no exception is thrown, then null is returned and `result` is set to the result of the expression. - Note that while $(D collectException) $(I can) be used to collect any - $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to - catch anything that is neither an $(D Exception) nor a type derived from - $(D Exception). So, do not use $(D collectException) to collect - non-$(D Exception)s unless you're sure that that's what you really want to + Note that while `collectException` $(I can) be used to collect any + `Throwable` and not just `Exception`s, it is generally ill-advised to + catch anything that is neither an `Exception` nor a type derived from + `Exception`. So, do not use `collectException` to collect + non-`Exception`s unless you're sure that that's what you really want to do. Params: @@ -723,14 +682,14 @@ T collectException(T = Exception, E)(lazy E expression, ref E result) /++ Catches and returns the exception thrown from the given expression. - If no exception is thrown, then null is returned. $(D E) can be - $(D void). - - Note that while $(D collectException) $(I can) be used to collect any - $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to - catch anything that is neither an $(D Exception) nor a type derived from - $(D Exception). So, do not use $(D collectException) to collect - non-$(D Exception)s unless you're sure that that's what you really want to + If no exception is thrown, then null is returned. `E` can be + `void`. + + Note that while `collectException` $(I can) be used to collect any + `Throwable` and not just `Exception`s, it is generally ill-advised to + catch anything that is neither an `Exception` nor a type derived from + `Exception`. So, do not use `collectException` to collect + non-`Exception`s unless you're sure that that's what you really want to do. Params: @@ -750,25 +709,26 @@ T collectException(T : Throwable = Exception, E)(lazy E expression) return null; } +/// @safe unittest { int foo() { throw new Exception("blah"); } - assert(collectException(foo())); + assert(collectException(foo()).msg == "blah"); } /++ Catches the exception thrown from the given expression and returns the msg property of that exception. If no exception is thrown, then null is - returned. $(D E) can be $(D void). + returned. `E` can be `void`. If an exception is thrown but it has an empty message, then - $(D emptyExceptionMsg) is returned. + `emptyExceptionMsg` is returned. - Note that while $(D collectExceptionMsg) $(I can) be used to collect any - $(D Throwable) and not just $(D Exception)s, it is generally ill-advised to - catch anything that is neither an $(D Exception) nor a type derived from - $(D Exception). So, do not use $(D collectExceptionMsg) to collect - non-$(D Exception)s unless you're sure that that's what you really want to + Note that while `collectExceptionMsg` $(I can) be used to collect any + `Throwable` and not just `Exception`s, it is generally ill-advised to + catch anything that is neither an `Exception` nor a type derived from + `Exception`. So, do not use `collectExceptionMsg` to collect + non-`Exception`s unless you're sure that that's what you really want to do. Params: @@ -808,18 +768,18 @@ enum emptyExceptionMsg = "<Empty Exception Message>"; /** * Casts a mutable array to an immutable array in an idiomatic - * manner. Technically, $(D assumeUnique) just inserts a cast, + * manner. Technically, `assumeUnique` just inserts a cast, * but its name documents assumptions on the part of the - * caller. $(D assumeUnique(arr)) should only be called when + * caller. `assumeUnique(arr)` should only be called when * there are no more active mutable aliases to elements of $(D - * arr). To strengthen this assumption, $(D assumeUnique(arr)) - * also clears $(D arr) before returning. Essentially $(D + * arr). To strengthen this assumption, `assumeUnique(arr)` + * also clears `arr` before returning. Essentially $(D * assumeUnique(arr)) indicates commitment from the caller that there - * is no more mutable access to any of $(D arr)'s elements + * is no more mutable access to any of `arr`'s elements * (transitively), and that all future accesses will be done through - * the immutable array returned by $(D assumeUnique). + * the immutable array returned by `assumeUnique`. * - * Typically, $(D assumeUnique) is used to return arrays from + * Typically, `assumeUnique` is used to return arrays from * functions that have allocated and built them. * * Params: @@ -829,6 +789,7 @@ enum emptyExceptionMsg = "<Empty Exception Message>"; * * Example: * + * $(RUNNABLE_EXAMPLE * ---- * string letters() * { @@ -840,14 +801,16 @@ enum emptyExceptionMsg = "<Empty Exception Message>"; * return assumeUnique(result); * } * ---- + * ) * - * The use in the example above is correct because $(D result) - * was private to $(D letters) and is inaccessible in writing + * The use in the example above is correct because `result` + * was private to `letters` and is inaccessible in writing * after the function returns. The following example shows an - * incorrect use of $(D assumeUnique). + * incorrect use of `assumeUnique`. * * Bad: * + * $(RUNNABLE_EXAMPLE * ---- * private char[] buffer; * string letters(char first, char last) @@ -862,11 +825,13 @@ enum emptyExceptionMsg = "<Empty Exception Message>"; * return assumeUnique(sneaky); // BAD * } * ---- + * ) * * The example above wreaks havoc on client code because it is * modifying arrays that callers considered immutable. To obtain an - * immutable array from the writable array $(D buffer), replace + * immutable array from the writable array `buffer`, replace * the last line with: + * * ---- * return to!(string)(sneaky); // not that sneaky anymore * ---- @@ -878,6 +843,8 @@ enum emptyExceptionMsg = "<Empty Exception Message>"; * marked as a pure function. The following example does not * need to call assumeUnique because the compiler can infer the * uniqueness of the array in the pure function: + * + * $(RUNNABLE_EXAMPLE * ---- * string letters() pure * { @@ -889,16 +856,17 @@ enum emptyExceptionMsg = "<Empty Exception Message>"; * return result; * } * ---- + * ) * * For more on infering uniqueness see the $(B unique) and * $(B lent) keywords in the - * $(HTTP archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava) + * $(HTTP www.cs.cmu.edu/~aldrich/papers/aldrich-dissertation.pdf, ArchJava) * language. * - * The downside of using $(D assumeUnique)'s + * The downside of using `assumeUnique`'s * convention-based usage is that at this time there is no * formal checking of the correctness of the assumption; - * on the upside, the idiomatic use of $(D assumeUnique) is + * on the upside, the idiomatic use of `assumeUnique` is * simple and rare enough to be tolerable. * */ @@ -921,34 +889,38 @@ immutable(T[U]) assumeUnique(T, U)(ref T[U] array) pure nothrow return result; } +/// @system unittest { - // @system due to assumeUnique int[] arr = new int[1]; - auto arr1 = assumeUnique(arr); - assert(is(typeof(arr1) == immutable(int)[]) && arr == null); + auto arr1 = arr.assumeUnique; + static assert(is(typeof(arr1) == immutable(int)[])); + assert(arr == null); + assert(arr1 == [0]); } -// @@@BUG@@@ -version (none) @system unittest +/// +@system unittest { int[string] arr = ["a":1]; - auto arr1 = assumeUnique(arr); - assert(is(typeof(arr1) == immutable(int[string])) && arr == null); + auto arr1 = arr.assumeUnique; + static assert(is(typeof(arr1) == immutable(int[string]))); + assert(arr == null); + assert(arr1.keys == ["a"]); } /** - * Wraps a possibly-throwing expression in a $(D nothrow) wrapper so that it - * can be called by a $(D nothrow) function. + * Wraps a possibly-throwing expression in a `nothrow` wrapper so that it + * can be called by a `nothrow` function. * * This wrapper function documents commitment on the part of the caller that * the appropriate steps have been taken to avoid whatever conditions may - * trigger an exception during the evaluation of $(D expr). If it turns out + * trigger an exception during the evaluation of `expr`. If it turns out * that the expression $(I does) throw at runtime, the wrapper will throw an - * $(D AssertError). + * `AssertError`. * - * (Note that $(D Throwable) objects such as $(D AssertError) that do not - * subclass $(D Exception) may be thrown even from $(D nothrow) functions, + * (Note that `Throwable` objects such as `AssertError` that do not + * subclass `Exception` may be thrown even from `nothrow` functions, * since they are considered to be serious runtime problems that cannot be * recovered from.) * @@ -984,7 +956,7 @@ T assumeWontThrow(T)(lazy T expr, /// @safe unittest { - import std.math : sqrt; + import std.math.algebraic : sqrt; // This function may throw. int squareRoot(int x) @@ -1030,37 +1002,41 @@ Params: source = The source object target = The target object -Returns: $(D true) if $(D source)'s representation embeds a pointer -that points to $(D target)'s representation or somewhere inside +Bugs: + The function is explicitly annotated `@nogc` because inference could fail, + see $(LINK2 https://issues.dlang.org/show_bug.cgi?id=17084, issue 17084). + +Returns: `true` if `source`'s representation embeds a pointer +that points to `target`'s representation or somewhere inside it. -If $(D source) is or contains a dynamic array, then, then these functions will check -if there is overlap between the dynamic array and $(D target)'s representation. +If `source` is or contains a dynamic array, then, then these functions will check +if there is overlap between the dynamic array and `target`'s representation. -If $(D source) is a class, then it will be handled as a pointer. +If `source` is a class, then it will be handled as a pointer. -If $(D target) is a pointer, a dynamic array or a class, then these functions will only -check if $(D source) points to $(D target), $(I not) what $(D target) references. +If `target` is a pointer, a dynamic array or a class, then these functions will only +check if `source` points to `target`, $(I not) what `target` references. -If $(D source) is or contains a union, then there may be either false positives or +If `source` is or contains a union or `void[n]`, then there may be either false positives or false negatives: -$(D doesPointTo) will return $(D true) if it is absolutely certain -$(D source) points to $(D target). It may produce false negatives, but never +`doesPointTo` will return `true` if it is absolutely certain +`source` points to `target`. It may produce false negatives, but never false positives. This function should be prefered when trying to validate input data. -$(D mayPointTo) will return $(D false) if it is absolutely certain -$(D source) does not point to $(D target). It may produce false positives, but never +`mayPointTo` will return `false` if it is absolutely certain +`source` does not point to `target`. It may produce false positives, but never false negatives. This function should be prefered for defensively choosing a code path. -Note: Evaluating $(D doesPointTo(x, x)) checks whether $(D x) has +Note: Evaluating $(D doesPointTo(x, x)) checks whether `x` has internal pointers. This should only be done as an assertive test, as the language is free to assume objects don't have internal pointers (TDPL 7.1.3.5). */ -bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @trusted pure nothrow +bool doesPointTo(S, T, Tdummy=void)(auto ref const S source, ref const T target) @nogc @trusted pure nothrow if (__traits(isRef, source) || isDynamicArray!S || isPointer!S || is(S == class)) { @@ -1080,8 +1056,11 @@ if (__traits(isRef, source) || isDynamicArray!S || } else static if (isStaticArray!S) { - foreach (size_t i; 0 .. S.length) - if (doesPointTo(source[i], target)) return true; + static if (!is(S == void[n], size_t n)) + { + foreach (ref s; source) + if (doesPointTo(s, target)) return true; + } return false; } else static if (isDynamicArray!S) @@ -1122,8 +1101,38 @@ if (__traits(isRef, source) || isDynamicArray!S || } else static if (isStaticArray!S) { - foreach (size_t i; 0 .. S.length) - if (mayPointTo(source[i], target)) return true; + static if (is(S == void[n], size_t n)) + { + static if (n >= (void[]).sizeof) + { + // could contain a slice, which could point at anything. + // But a void[N] that is all 0 cannot point anywhere + import std.algorithm.searching : any; + if (__ctfe || any(cast(ubyte[]) source[])) + return true; + } + else static if (n >= (void*).sizeof) + { + // Reinterpreting cast is impossible during ctfe + if (__ctfe) + return true; + + // Only check for properly aligned pointers + enum al = (void*).alignof - 1; + const base = cast(size_t) &source; + const alBase = (base + al) & ~al; + + if ((n - (alBase - base)) >= (void*).sizeof && + mayPointTo(*(cast(void**) alBase), target)) + return true; + } + } + else + { + foreach (size_t i; 0 .. S.length) + if (mayPointTo(source[i], target)) return true; + } + return false; } else static if (isDynamicArray!S) @@ -1179,9 +1188,12 @@ bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) @system unittest { int i; + // trick the compiler when initializing slice + // https://issues.dlang.org/show_bug.cgi?id=18637 + int* p = &i; int[] slice = [0, 1, 2, 3, 4]; int[5] arr = [0, 1, 2, 3, 4]; - int*[] slicep = [&i]; + int*[] slicep = [p]; int*[1] arrp = [&i]; // A slice points to all of its members: @@ -1241,6 +1253,37 @@ bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) assert(b.doesPointTo(*aLoc)); // b points to where a is pointing } + +version (StdUnittest) +{ + // https://issues.dlang.org/show_bug.cgi?id=17084 + // the bug doesn't happen if these declarations are in the unittest block + // (static or not). + private struct Page17084 + { + URL17084 url; + int opCmp(P)(P) { return 0; } + int opCmp(P)(shared(P)) shared { return 0; } + } + + private struct URL17084 + { + int[] queryParams; + string toString()() const { return ""; } + alias toString this; + } +} + +// https://issues.dlang.org/show_bug.cgi?id=17084 +@system unittest +{ + import std.algorithm.sorting : sort; + Page17084[] s; + sort(s); + shared(Page17084)[] p; + sort(p); +} + @system unittest { struct S1 { int a; S1 * b; } @@ -1337,6 +1380,57 @@ bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) assert( doesPointTo(ss, a)); //The array contains a struct that points to a assert(!doesPointTo(ss, b)); //The array doesn't contains a struct that points to b assert(!doesPointTo(ss, ss)); //The array doesn't point itself. + + // https://issues.dlang.org/show_bug.cgi?id=20426 + align((void*).alignof) void[32] voidArr = void; + (cast(void*[]) voidArr[])[] = null; // Ensure no false pointers + + // zeroed void ranges can't point at anything + assert(!mayPointTo(voidArr, a)); + assert(!mayPointTo(voidArr, b)); + + *cast(void**) &voidArr[16] = &a; // Pointers should be found + + alias SA = void[size_t.sizeof + 3]; + SA *smallArr1 = cast(SA*)&voidArr; + SA *smallArr2 = cast(SA*)&(voidArr[16]); + + // But it should only consider properly aligned pointers + // Write single bytes to avoid issues due to misaligned writes + void*[1] tmp = [&b]; + (cast(ubyte[]) voidArr[3 .. 3 + (void*).sizeof])[] = cast(ubyte[]) tmp[]; + + + assert( mayPointTo(*smallArr2, a)); + assert(!mayPointTo(*smallArr1, b)); + + assert(!doesPointTo(voidArr, a)); // Value might be a false pointer + assert(!doesPointTo(voidArr, b)); + + SA *smallArr3 = cast(SA *) &voidArr[13]; // Works for weird sizes/alignments + assert( mayPointTo(*smallArr3, a)); + assert(!mayPointTo(*smallArr3, b)); + + assert(!doesPointTo(*smallArr3, a)); + assert(!doesPointTo(*smallArr3, b)); + + auto v3 = cast(void[3]*) &voidArr[16]; // Arrays smaller than pointers are ignored + assert(!mayPointTo(*v3, a)); + assert(!mayPointTo(*v3, b)); + + assert(!doesPointTo(*v3, a)); + assert(!doesPointTo(*v3, b)); + + assert(mayPointTo(voidArr, a)); // slice-contiaining void[N] might point at anything + assert(mayPointTo(voidArr, b)); + + static assert(() { + void[16] arr1 = void; + void[size_t.sizeof] arr2 = void; + int var; + return mayPointTo(arr1, var) && !doesPointTo(arr1, var) && + mayPointTo(arr2, var) && !doesPointTo(arr2, var); + }()); } @@ -1425,7 +1519,7 @@ bool mayPointTo(S, T)(auto ref const shared S source, ref const shared T target) } /+ -Returns true if the field at index $(D i) in ($D T) shares its address with another field. +Returns true if the field at index `i` in ($D T) shares its address with another field. Note: This does not merelly check if the field is a member of an union, but also that it is not a single child. @@ -1510,53 +1604,57 @@ package string errnoString(int errno) nothrow @trusted } /********************* - * Thrown if errors that set $(D errno) occur. + * Thrown if errors that set `errno` occur. */ class ErrnoException : Exception { - final @property uint errno() { return _errno; } /// Operating system error code. + /// Operating system error code. + final @property uint errno() nothrow pure @nogc @safe { return _errno; } private uint _errno; /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code. - this(string msg, string file = null, size_t line = 0) @trusted + this(string msg, string file = null, size_t line = 0) @safe { import core.stdc.errno : errno; this(msg, errno, file, line); } /// Constructor which takes an error message and error code. - this(string msg, int errno, string file = null, size_t line = 0) @trusted + this(string msg, int errno, string file = null, size_t line = 0) @safe { _errno = errno; super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line); } +} - @system unittest - { - import core.stdc.errno : errno, EAGAIN; +/// +@safe unittest +{ + import core.stdc.errno : EAGAIN; + auto ex = new ErrnoException("oh no", EAGAIN); + assert(ex.errno == EAGAIN); +} - auto old = errno; - scope(exit) errno = old; +/// errno is used by default if no explicit error code is provided +@safe unittest +{ + import core.stdc.errno : errno, EAGAIN; - errno = EAGAIN; - auto ex = new ErrnoException("oh no"); - assert(ex.errno == EAGAIN); - } + auto old = errno; + scope(exit) errno = old; - @system unittest - { - import core.stdc.errno : EAGAIN; - auto ex = new ErrnoException("oh no", EAGAIN); - assert(ex.errno == EAGAIN); - } + // fake that errno got set by the callee + errno = EAGAIN; + auto ex = new ErrnoException("oh no"); + assert(ex.errno == EAGAIN); } /++ ML-style functional exception handling. Runs the supplied expression and - returns its result. If the expression throws a $(D Throwable), runs the + returns its result. If the expression throws a `Throwable`, runs the supplied error handler instead and return its result. The error handler's type must be the same as the expression's type. Params: - E = The type of $(D Throwable)s to catch. Defaults to $(D Exception) + E = The type of `Throwable`s to catch. Defaults to `Exception` T1 = The type of the expression. T2 = The return type of the error handler. expression = The expression to run and return its result. @@ -1565,54 +1663,7 @@ class ErrnoException : Exception Returns: expression, if it does not throw. Otherwise, returns the result of errorHandler. - - Example: - -------------------- - //Revert to a default value upon an error: - assert("x".to!int().ifThrown(0) == 0); - -------------------- - - You can also chain multiple calls to ifThrown, each capturing errors from the - entire preceding expression. - - Example: - -------------------- - //Chaining multiple calls to ifThrown to attempt multiple things in a row: - string s="true"; - assert(s.to!int(). - ifThrown(cast(int) s.to!double()). - ifThrown(cast(int) s.to!bool()) - == 1); - - //Respond differently to different types of errors - assert(enforce("x".to!int() < 1).to!string() - .ifThrown!ConvException("not a number") - .ifThrown!Exception("number too small") - == "not a number"); - -------------------- - - The expression and the errorHandler must have a common type they can both - be implicitly casted to, and that type will be the type of the compound - expression. - - Example: - -------------------- - //null and new Object have a common type(Object). - static assert(is(typeof(null.ifThrown(new Object())) == Object)); - static assert(is(typeof((new Object()).ifThrown(null)) == Object)); - - //1 and new Object do not have a common type. - static assert(!__traits(compiles, 1.ifThrown(new Object()))); - static assert(!__traits(compiles, (new Object()).ifThrown(1))); - -------------------- - - If you need to use the actual thrown exception, you can use a delegate. - Example: - -------------------- - //Use a lambda to get the thrown object. - assert("%s".format().ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException"); - -------------------- - +/ ++/ //lazy version CommonType!(T1, T2) ifThrown(E : Throwable = Exception, T1, T2)(lazy scope T1 expression, lazy scope T2 errorHandler) { @@ -1675,6 +1726,59 @@ CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate } } +/// Revert to a default value upon an error: +@safe unittest +{ + import std.conv : to; + assert("x".to!int.ifThrown(0) == 0); +} + +/** +Chain multiple calls to ifThrown, each capturing errors from the +entire preceding expression. +*/ +@safe unittest +{ + import std.conv : ConvException, to; + string s = "true"; + assert(s.to!int.ifThrown(cast(int) s.to!double) + .ifThrown(cast(int) s.to!bool) == 1); + + s = "2.0"; + assert(s.to!int.ifThrown(cast(int) s.to!double) + .ifThrown(cast(int) s.to!bool) == 2); + + // Respond differently to different types of errors + alias orFallback = (lazy a) => a.ifThrown!ConvException("not a number") + .ifThrown!Exception("number too small"); + + assert(orFallback(enforce("x".to!int < 1).to!string) == "not a number"); + assert(orFallback(enforce("2".to!int < 1).to!string) == "number too small"); +} + +/** +The expression and the errorHandler must have a common type they can both +be implicitly casted to, and that type will be the type of the compound +expression. +*/ +@safe unittest +{ + // null and new Object have a common type(Object). + static assert(is(typeof(null.ifThrown(new Object())) == Object)); + static assert(is(typeof((new Object()).ifThrown(null)) == Object)); + + // 1 and new Object do not have a common type. + static assert(!__traits(compiles, 1.ifThrown(new Object()))); + static assert(!__traits(compiles, (new Object()).ifThrown(1))); +} + +/// Use a lambda to get the thrown object. +@system unittest +{ + import std.format : format; + assert("%s".format.ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException"); +} + //Verify Examples @system unittest { @@ -1745,22 +1849,22 @@ CommonType!(T1, T2) ifThrown(T1, T2)(lazy scope T1 expression, scope T2 delegate static assert(!__traits(compiles, (new Object()).ifThrown(e=>1))); } -version (unittest) package -@property void assertCTFEable(alias dg)() +version (StdUnittest) package +void assertCTFEable(alias dg)() { static assert({ cast(void) dg(); return true; }()); cast(void) dg(); } -/** This $(D enum) is used to select the primitives of the range to handle by the - $(LREF handle) range wrapper. The values of the $(D enum) can be $(D OR)'d to +/** This `enum` is used to select the primitives of the range to handle by the + $(LREF handle) range wrapper. The values of the `enum` can be `OR`'d to select multiple primitives to be handled. - $(D RangePrimitive.access) is a shortcut for the access primitives; $(D front), - $(D back) and $(D opIndex). + `RangePrimitive.access` is a shortcut for the access primitives; `front`, + `back` and `opIndex`. - $(D RangePrimitive.pop) is a shortcut for the mutating primitives; - $(D popFront) and $(D popBack). + `RangePrimitive.pop` is a shortcut for the mutating primitives; + `popFront` and `popBack`. */ enum RangePrimitive { @@ -1778,31 +1882,65 @@ enum RangePrimitive pop = popFront | popBack, /// Ditto } +/// +pure @safe unittest +{ + import std.algorithm.comparison : equal; + import std.algorithm.iteration : map, splitter; + import std.conv : to, ConvException; + + auto s = "12,1337z32,54,2,7,9,1z,6,8"; + + // The next line composition will throw when iterated + // as some elements of the input do not convert to integer + auto r = s.splitter(',').map!(a => to!int(a)); + + // Substitute 0 for cases of ConvException + auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0); + assert(h.equal([12, 0, 54, 2, 7, 9, 0, 6, 8])); +} + +/// +pure @safe unittest +{ + import std.algorithm.comparison : equal; + import std.range : retro; + import std.utf : UTFException; + + auto str = "hello\xFFworld"; // 0xFF is an invalid UTF-8 code unit + + auto handled = str.handle!(UTFException, RangePrimitive.access, + (e, r) => ' '); // Replace invalid code points with spaces + + assert(handled.equal("hello world")); // `front` is handled, + assert(handled.retro.equal("dlrow olleh")); // as well as `back` +} + /** Handle exceptions thrown from range primitives. Use the $(LREF RangePrimitive) enum to specify which primitives to _handle. -Multiple range primitives can be handled at once by using the $(D OR) operator -or the pseudo-primitives $(D RangePrimitive.access) and $(D RangePrimitive.pop). +Multiple range primitives can be handled at once by using the `OR` operator +or the pseudo-primitives `RangePrimitive.access` and `RangePrimitive.pop`. All handled primitives must have return types or values compatible with the user-supplied handler. Params: - E = The type of $(D Throwable) to _handle. + E = The type of `Throwable` to _handle. primitivesToHandle = Set of range primitives to _handle. handler = The callable that is called when a handled primitive throws a - $(D Throwable) of type $(D E). The handler must accept arguments of + `Throwable` of type `E`. The handler must accept arguments of the form $(D E, ref IRange) and its return value is used as the primitive's - return value whenever $(D E) is thrown. For $(D opIndex), the handler can + return value whenever `E` is thrown. For `opIndex`, the handler can optionally recieve a third argument; the index that caused the exception. input = The range to _handle. -Returns: A wrapper $(D struct) that preserves the range interface of $(D input). +Returns: A wrapper `struct` that preserves the range interface of `input`. Note: Infinite ranges with slicing support must return an instance of $(REF Take, std,range) when sliced with a specific lower and upper -bound (see $(REF hasSlicing, std,range,primitives)); $(D handle) deals with -this by $(D take)ing 0 from the return value of the handler function and +bound (see $(REF hasSlicing, std,range,primitives)); `handle` deals with +this by `take`ing 0 from the return value of the handler function and returning that when an exception is caught. */ auto handle(E : Throwable, RangePrimitive primitivesToHandle, alias handler, Range)(Range input) |