aboutsummaryrefslogtreecommitdiff
path: root/libphobos/testsuite
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2019-06-18 20:42:10 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2021-11-30 16:53:28 +0100
commit5fee5ec362f7a243f459e6378fd49dfc89dc9fb5 (patch)
tree61d1bdbca854a903c0860406f457f06b2040be7a /libphobos/testsuite
parentb3f60112edcb85b459e60f66c44a55138b1cef49 (diff)
downloadgcc-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/testsuite')
-rw-r--r--libphobos/testsuite/lib/libphobos.exp60
-rw-r--r--libphobos/testsuite/libphobos.aa/test_aa.d79
-rw-r--r--libphobos/testsuite/libphobos.allocations/alloc_from_assert.d25
-rw-r--r--libphobos/testsuite/libphobos.betterc/betterc.exp27
-rw-r--r--libphobos/testsuite/libphobos.betterc/test18828.d10
-rw-r--r--libphobos/testsuite/libphobos.betterc/test19416.d14
-rw-r--r--libphobos/testsuite/libphobos.betterc/test19421.d13
-rw-r--r--libphobos/testsuite/libphobos.betterc/test19561.d16
-rw-r--r--libphobos/testsuite/libphobos.betterc/test19924.d15
-rw-r--r--libphobos/testsuite/libphobos.betterc/test20088.d14
-rw-r--r--libphobos/testsuite/libphobos.betterc/test20613.d18
-rw-r--r--libphobos/testsuite/libphobos.config/config.exp46
-rw-r--r--libphobos/testsuite/libphobos.config/test19433.d7
-rw-r--r--libphobos/testsuite/libphobos.config/test20459.d5
-rw-r--r--libphobos/testsuite/libphobos.druntime/druntime.exp2
-rw-r--r--libphobos/testsuite/libphobos.druntime_shared/druntime_shared.exp2
-rw-r--r--libphobos/testsuite/libphobos.exceptions/assert_fail.d564
-rw-r--r--libphobos/testsuite/libphobos.exceptions/catch_in_finally.d191
-rw-r--r--libphobos/testsuite/libphobos.exceptions/future_message.d71
-rw-r--r--libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d37
-rw-r--r--libphobos/testsuite/libphobos.exceptions/refcounted.d96
-rw-r--r--libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d15
-rw-r--r--libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d11
-rw-r--r--libphobos/testsuite/libphobos.exceptions/unknown_gc.d4
-rw-r--r--libphobos/testsuite/libphobos.gc/attributes.d30
-rw-r--r--libphobos/testsuite/libphobos.gc/forkgc.d36
-rw-r--r--libphobos/testsuite/libphobos.gc/forkgc2.d22
-rw-r--r--libphobos/testsuite/libphobos.gc/gc.exp27
-rw-r--r--libphobos/testsuite/libphobos.gc/nocollect.d15
-rw-r--r--libphobos/testsuite/libphobos.gc/precisegc.d126
-rw-r--r--libphobos/testsuite/libphobos.gc/recoverfree.d13
-rw-r--r--libphobos/testsuite/libphobos.gc/sigmaskgc.d42
-rw-r--r--libphobos/testsuite/libphobos.gc/startbackgc.d22
-rw-r--r--libphobos/testsuite/libphobos.hash/test_hash.d140
-rw-r--r--libphobos/testsuite/libphobos.imports/bug18193.d4
-rw-r--r--libphobos/testsuite/libphobos.imports/imports.exp29
-rw-r--r--libphobos/testsuite/libphobos.init_fini/custom_gc.d203
-rw-r--r--libphobos/testsuite/libphobos.init_fini/test18996.d13
-rw-r--r--libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d78
-rw-r--r--libphobos/testsuite/libphobos.lifetime/lifetime.exp27
-rw-r--r--libphobos/testsuite/libphobos.phobos/phobos.exp2
-rw-r--r--libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp2
-rw-r--r--libphobos/testsuite/libphobos.shared/host.c8
-rw-r--r--libphobos/testsuite/libphobos.shared/link_mod_collision.d5
-rw-r--r--libphobos/testsuite/libphobos.shared/load.d1
-rw-r--r--libphobos/testsuite/libphobos.shared/load_13414.d13
-rw-r--r--libphobos/testsuite/libphobos.shared/load_mod_collision.d14
-rw-r--r--libphobos/testsuite/libphobos.thread/external_threads.d50
-rw-r--r--libphobos/testsuite/libphobos.thread/fiber_guard_page.d4
-rw-r--r--libphobos/testsuite/libphobos.thread/join_detach.d20
-rw-r--r--libphobos/testsuite/libphobos.thread/test_import.d7
-rw-r--r--libphobos/testsuite/libphobos.thread/tlsgc_sections.d61
-rw-r--r--libphobos/testsuite/libphobos.thread/tlsstack.d38
-rw-r--r--libphobos/testsuite/libphobos.typeinfo/enum_.d21
-rw-r--r--libphobos/testsuite/libphobos.typeinfo/isbaseof.d46
-rw-r--r--libphobos/testsuite/libphobos.unittest/customhandler.d21
-rw-r--r--libphobos/testsuite/libphobos.unittest/unittest.exp53
-rwxr-xr-xlibphobos/testsuite/testsuite_flags.in2
58 files changed, 2465 insertions, 72 deletions
diff --git a/libphobos/testsuite/lib/libphobos.exp b/libphobos/testsuite/lib/libphobos.exp
index 2af430a..66e3e80 100644
--- a/libphobos/testsuite/lib/libphobos.exp
+++ b/libphobos/testsuite/lib/libphobos.exp
@@ -54,6 +54,10 @@ proc libphobos-dg-test { prog do_what extra_tool_flags } {
# Set up the compiler flags, based on what we're going to do.
switch $do_what {
+ "compile" {
+ set compile_type "assembly"
+ set output_file "[file rootname [file tail $prog]].s"
+ }
"run" {
set compile_type "executable"
# FIXME: "./" is to cope with "." not being in $PATH.
@@ -89,8 +93,52 @@ proc libphobos-dg-test { prog do_what extra_tool_flags } {
return [list $comp_output $output_file]
}
+# Override the DejaGnu dg-test in order to clear flags after a test, as
+# is done for compiler tests in gcc-dg.exp.
+
+if { [info procs saved-dg-test] == [list] } {
+ rename dg-test saved-dg-test
+
+ proc dg-test { args } {
+ global additional_prunes
+ global errorInfo
+ global testname_with_flags
+ global shouldfail
+
+ if { [ catch { eval saved-dg-test $args } errmsg ] } {
+ set saved_info $errorInfo
+ set additional_prunes ""
+ set shouldfail 0
+ if [info exists testname_with_flags] {
+ unset testname_with_flags
+ }
+ unset_timeout_vars
+ error $errmsg $saved_info
+ }
+ set additional_prunes ""
+ set shouldfail 0
+ unset_timeout_vars
+ if [info exists testname_with_flags] {
+ unset testname_with_flags
+ }
+ }
+}
+
+# Prune messages from gdc that aren't useful.
+
+set additional_prunes ""
+
proc libphobos-dg-prune { system text } {
+ global additional_prunes
+
+ foreach p $additional_prunes {
+ if { [string length $p] > 0 } {
+ # Following regexp matches a complete line containing $p.
+ regsub -all "(^|\n)\[^\n\]*$p\[^\n\]*" $text "" text
+ }
+ }
+
# Ignore harmless warnings from Xcode.
regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text
@@ -281,6 +329,18 @@ proc libphobos_skipped_test_p { test } {
return "skipped test"
}
+# Prune any messages matching ARGS[1] (a regexp) from test output.
+proc dg-prune-output { args } {
+ global additional_prunes
+
+ if { [llength $args] != 2 } {
+ error "[lindex $args 1]: need one argument"
+ return
+ }
+
+ lappend additional_prunes [lindex $args 1]
+}
+
# Return true if the curl library is supported on the target.
proc check_effective_target_libcurl_available { } {
return [check_no_compiler_messages libcurl_available executable {
diff --git a/libphobos/testsuite/libphobos.aa/test_aa.d b/libphobos/testsuite/libphobos.aa/test_aa.d
index d6222b1..11ad2f9 100644
--- a/libphobos/testsuite/libphobos.aa/test_aa.d
+++ b/libphobos/testsuite/libphobos.aa/test_aa.d
@@ -30,6 +30,8 @@ void main()
issue15367();
issue16974();
issue18071();
+ issue20440();
+ issue21442();
testIterationWithConst();
testStructArrayKey();
miscTests1();
@@ -286,21 +288,20 @@ void testUpdate2()
assert(updated);
}
-void testByKey1()
+void testByKey1() @safe
{
- static assert(!__traits(compiles,
- () @safe {
- struct BadValue
- {
- int x;
- this(this) @safe { *(cast(ubyte*)(null) + 100000) = 5; } // not @safe
- alias x this;
- }
+ static struct BadValue
+ {
+ int x;
+ this(this) @system { *(cast(ubyte*)(null) + 100000) = 5; } // not @safe
+ alias x this;
+ }
- BadValue[int] aa;
- () @safe { auto x = aa.byKey.front; } ();
- }
- ));
+ BadValue[int] aa;
+
+ // FIXME: Should be @system because of the postblit
+ if (false)
+ auto x = aa.byKey.front;
}
void testByKey2() nothrow pure
@@ -690,6 +691,58 @@ void issue18071()
() @safe { assert(f.byKey.empty); }();
}
+/// Test that `require` works even with types whose opAssign
+/// doesn't return a reference to the receiver.
+/// https://issues.dlang.org/show_bug.cgi?id=20440
+void issue20440() @safe
+{
+ static struct S
+ {
+ int value;
+ auto opAssign(S s) {
+ this.value = s.value;
+ return this;
+ }
+ }
+ S[S] aa;
+ assert(aa.require(S(1), S(2)) == S(2));
+ assert(aa[S(1)] == S(2));
+}
+
+///
+void issue21442()
+{
+ import core.memory;
+
+ size_t[size_t] glob;
+
+ class Foo
+ {
+ size_t count;
+
+ this (size_t entries) @safe
+ {
+ this.count = entries;
+ foreach (idx; 0 .. entries)
+ glob[idx] = idx;
+ }
+
+ ~this () @safe
+ {
+ foreach (idx; 0 .. this.count)
+ glob.remove(idx);
+ }
+ }
+
+ void bar () @safe
+ {
+ Foo f = new Foo(16);
+ }
+
+ bar();
+ GC.collect(); // Needs to happen from a GC collection
+}
+
/// Verify iteration with const.
void testIterationWithConst()
{
diff --git a/libphobos/testsuite/libphobos.allocations/alloc_from_assert.d b/libphobos/testsuite/libphobos.allocations/alloc_from_assert.d
new file mode 100644
index 0000000..a377cd9
--- /dev/null
+++ b/libphobos/testsuite/libphobos.allocations/alloc_from_assert.d
@@ -0,0 +1,25 @@
+import core.exception;
+import core.memory;
+
+class FailFinalization
+{
+ int magic;
+
+ ~this () @nogc nothrow
+ {
+ try
+ assert(this.magic == 42);
+ catch (AssertError) {}
+ }
+}
+
+void foo ()
+{
+ auto dangling = new FailFinalization();
+}
+
+void main()
+{
+ foo();
+ GC.collect();
+}
diff --git a/libphobos/testsuite/libphobos.betterc/betterc.exp b/libphobos/testsuite/libphobos.betterc/betterc.exp
new file mode 100644
index 0000000..e5e9b84
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/betterc.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.d]]
+
+# Main loop.
+dg-runtest $tests "-fno-druntime" $DEFAULT_DFLAGS
+
+# All done.
+dg-finish
diff --git a/libphobos/testsuite/libphobos.betterc/test18828.d b/libphobos/testsuite/libphobos.betterc/test18828.d
new file mode 100644
index 0000000..db0530d
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test18828.d
@@ -0,0 +1,10 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=18828
+
+struct S18828 { }
+
+extern(C) void main()
+{
+ S18828 s;
+ destroy(s);
+}
diff --git a/libphobos/testsuite/libphobos.betterc/test19416.d b/libphobos/testsuite/libphobos.betterc/test19416.d
new file mode 100644
index 0000000..aff93d3
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test19416.d
@@ -0,0 +1,14 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19416
+
+import core.stdc.stdlib : malloc, free;
+import core.exception : onOutOfMemoryError;
+
+extern(C) void main()
+{
+ auto m = malloc(1);
+ if (!m)
+ onOutOfMemoryError();
+ else
+ free(m);
+}
diff --git a/libphobos/testsuite/libphobos.betterc/test19421.d b/libphobos/testsuite/libphobos.betterc/test19421.d
new file mode 100644
index 0000000..2427c5e
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test19421.d
@@ -0,0 +1,13 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19421
+
+import core.memory;
+
+extern(C) void main() @nogc nothrow pure
+{
+ auto p = pureMalloc(1);
+ p = pureRealloc(p, 2);
+ if (p) pureFree(p);
+ p = pureCalloc(1, 1);
+ if (p) pureFree(p);
+}
diff --git a/libphobos/testsuite/libphobos.betterc/test19561.d b/libphobos/testsuite/libphobos.betterc/test19561.d
new file mode 100644
index 0000000..96ecec51
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test19561.d
@@ -0,0 +1,16 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19561
+
+import core.memory;
+
+extern(C) void main() @nogc nothrow pure
+{
+ int[3] a, b;
+ a[] = 0;
+ a[] = b[];
+ //FIXME: Next line requires compiler change.
+ //a[] = 1; // error: undefined reference to '_memset32'
+ a[] += 1;
+ a[] += b[];
+ int[3] c = a[] + b[];
+}
diff --git a/libphobos/testsuite/libphobos.betterc/test19924.d b/libphobos/testsuite/libphobos.betterc/test19924.d
new file mode 100644
index 0000000..e9a93ca
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test19924.d
@@ -0,0 +1,15 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=19924
+
+import core.bitop;
+
+extern(C) void main()
+{
+ uint a = 0x01_23_45_67;
+ a = bswap(a);
+ assert(a == 0x67_45_23_01);
+
+ ulong b = 0x01_23_45_67_89_ab_cd_ef;
+ b = bswap(b);
+ assert(b == 0xef_cd_ab_89_67_45_23_01);
+}
diff --git a/libphobos/testsuite/libphobos.betterc/test20088.d b/libphobos/testsuite/libphobos.betterc/test20088.d
new file mode 100644
index 0000000..a809041
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test20088.d
@@ -0,0 +1,14 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20088
+
+struct S {
+ int i;
+}
+
+extern(C) int main() @nogc nothrow pure
+{
+ S[2] s = [S(1),S(2)];
+ void[] v = cast(void[])s;
+ S[] p = cast(S[])v; // cast of void[] to S[] triggers __ArrayCast template function
+ return 0;
+}
diff --git a/libphobos/testsuite/libphobos.betterc/test20613.d b/libphobos/testsuite/libphobos.betterc/test20613.d
new file mode 100644
index 0000000..b03e2d1
--- /dev/null
+++ b/libphobos/testsuite/libphobos.betterc/test20613.d
@@ -0,0 +1,18 @@
+/*******************************************/
+// https://issues.dlang.org/show_bug.cgi?id=20613
+
+extern(C) int main() @nogc nothrow pure
+{
+ auto s = "F";
+ final switch(s)
+ {
+ case "A": break;
+ case "B": break;
+ case "C": break;
+ case "D": break;
+ case "E": break;
+ case "F": break;
+ case "G": break;
+ }
+ return 0;
+}
diff --git a/libphobos/testsuite/libphobos.config/config.exp b/libphobos/testsuite/libphobos.config/config.exp
new file mode 100644
index 0000000..e8f4d94
--- /dev/null
+++ b/libphobos/testsuite/libphobos.config/config.exp
@@ -0,0 +1,46 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib libphobos-dg.exp
+
+set dg-output-text [list]
+
+# Test, arguments to pass to the test program, and return code.
+set config_test_list [list \
+ { test19433 "--DRT-dont-eat-me" 0 } \
+ { test20459 "foo bar -- --DRT-gcopts=profile:1" 0 } \
+]
+
+# Initialize dg.
+dg-init
+
+# Main loop.
+foreach config_test $config_test_list {
+ set test "$srcdir/$subdir/[lindex $config_test 0].d"
+
+ set libphobos_run_args "[lindex $config_test 1]"
+ set shouldfail [lindex $config_test 2]
+ set libphobos_test_name "[dg-trim-dirname $srcdir $test] $libphobos_run_args"
+
+ dg-runtest $test "" $DEFAULT_DFLAGS
+
+ set libphobos_test_name ""
+ set shouldfail 0
+ set libphobos_run_args ""
+}
+
+# All done.
+dg-finish
diff --git a/libphobos/testsuite/libphobos.config/test19433.d b/libphobos/testsuite/libphobos.config/test19433.d
new file mode 100644
index 0000000..1c58145
--- /dev/null
+++ b/libphobos/testsuite/libphobos.config/test19433.d
@@ -0,0 +1,7 @@
+extern(C) __gshared bool rt_cmdline_enabled = false;
+
+void main(string[] args)
+{
+ assert(args.length == 2);
+ assert(args[1] == "--DRT-dont-eat-me");
+}
diff --git a/libphobos/testsuite/libphobos.config/test20459.d b/libphobos/testsuite/libphobos.config/test20459.d
new file mode 100644
index 0000000..248720d
--- /dev/null
+++ b/libphobos/testsuite/libphobos.config/test20459.d
@@ -0,0 +1,5 @@
+void main (string[] args)
+{
+ assert(args.length == 5);
+ assert(args[1 .. $] == [ "foo", "bar", "--", "--DRT-gcopts=profile:1" ]);
+}
diff --git a/libphobos/testsuite/libphobos.druntime/druntime.exp b/libphobos/testsuite/libphobos.druntime/druntime.exp
index daedfd7..5342d45 100644
--- a/libphobos/testsuite/libphobos.druntime/druntime.exp
+++ b/libphobos/testsuite/libphobos.druntime/druntime.exp
@@ -22,7 +22,7 @@ if { ![isnative] } {
# Gather a list of all tests.
set tests [lsort [filter_libphobos_unittests [find $srcdir/../libdruntime "*.d"]]]
-set version_flags ""
+set version_flags "-fversion=CoreUnittest"
if { [is-effective-target linux_pre_2639] } {
lappend version_flags "-fversion=Linux_Pre_2639"
diff --git a/libphobos/testsuite/libphobos.druntime_shared/druntime_shared.exp b/libphobos/testsuite/libphobos.druntime_shared/druntime_shared.exp
index 51f9c2c..67edab9 100644
--- a/libphobos/testsuite/libphobos.druntime_shared/druntime_shared.exp
+++ b/libphobos/testsuite/libphobos.druntime_shared/druntime_shared.exp
@@ -22,7 +22,7 @@ if { ![isnative] || ![is-effective-target shared] } {
# Gather a list of all tests.
set tests [lsort [filter_libphobos_unittests [find $srcdir/../libdruntime "*.d"]]]
-set version_flags ""
+set version_flags "-fversion=CoreUnittest -fversion=Shared"
if { [is-effective-target linux_pre_2639] } {
lappend version_flags "-fversion=Linux_Pre_2639"
diff --git a/libphobos/testsuite/libphobos.exceptions/assert_fail.d b/libphobos/testsuite/libphobos.exceptions/assert_fail.d
new file mode 100644
index 0000000..79b3cb8
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/assert_fail.d
@@ -0,0 +1,564 @@
+import core.stdc.stdio : fprintf, stderr;
+import core.internal.dassert : _d_assert_fail;
+
+void test(string comp = "==", A, B)(A a, B b, string msg, size_t line = __LINE__)
+{
+ test(_d_assert_fail!(A)(comp, a, b), msg, line);
+}
+
+void test(const string actual, const string expected, size_t line = __LINE__)
+{
+ import core.exception : AssertError;
+
+ if (actual != expected)
+ {
+ const msg = "Mismatch!\nExpected: <" ~ expected ~ ">\nActual: <" ~ actual ~ '>';
+ throw new AssertError(msg, __FILE__, line);
+ }
+}
+
+void testIntegers()
+{
+ test(1, 2, "1 != 2");
+ test(-10, 8, "-10 != 8");
+ test(byte.min, byte.max, "-128 != 127");
+ test(ubyte.min, ubyte.max, "0 != 255");
+ test(short.min, short.max, "-32768 != 32767");
+ test(ushort.min, ushort.max, "0 != 65535");
+ test(int.min, int.max, "-2147483648 != 2147483647");
+ test(uint.min, uint.max, "0 != 4294967295");
+ test(long.min, long.max, "-9223372036854775808 != 9223372036854775807");
+ test(ulong.min, ulong.max, "0 != 18446744073709551615");
+ test(shared(ulong).min, shared(ulong).max, "0 != 18446744073709551615");
+
+ int testFun() { return 1; }
+ test(testFun(), 2, "1 != 2");
+}
+
+void testIntegerComparisons()
+{
+ test!"!="(2, 2, "2 == 2");
+ test!"<"(2, 1, "2 >= 1");
+ test!"<="(2, 1, "2 > 1");
+ test!">"(1, 2, "1 <= 2");
+ test!">="(1, 2, "1 < 2");
+}
+
+void testFloatingPoint()
+{
+ if (__ctfe)
+ {
+ test(float.max, -float.max, "<float not supported> != <float not supported>");
+ test(double.max, -double.max, "<double not supported> != <double not supported>");
+ test(real(1), real(-1), "<real not supported> != <real not supported>");
+ }
+ else
+ {
+ test(1.5, 2.5, "1.5 != 2.5");
+ test(float.max, -float.max, "3.40282e+38 != -3.40282e+38");
+ test(double.max, -double.max, "1.79769e+308 != -1.79769e+308");
+ test(real(1), real(-1), "1 != -1");
+ }
+}
+
+void testPointers()
+{
+ static struct S
+ {
+ string toString() const { return "S(...)"; }
+ }
+
+ static if ((void*).sizeof == 4)
+ enum ptr = "0x12345670";
+ else
+ enum ptr = "0x123456789abcdef0";
+
+ int* p = cast(int*) mixin(ptr);
+ test(cast(S*) p, p, ptr ~ " != " ~ ptr);
+}
+
+void testStrings()
+{
+ test("foo", "bar", `"foo" != "bar"`);
+ test("", "bar", `"" != "bar"`);
+
+ char[] dlang = "dlang".dup;
+ const(char)[] rust = "rust";
+ test(dlang, rust, `"dlang" != "rust"`);
+
+ // https://issues.dlang.org/show_bug.cgi?id=20322
+ test("left"w, "right"w, `"left" != "right"`);
+ test("left"d, "right"d, `"left" != "right"`);
+
+ test('A', 'B', "'A' != 'B'");
+ test(wchar('❤'), wchar('∑'), "'❤' != '∑'");
+ test(dchar('❤'), dchar('∑'), "'❤' != '∑'");
+
+ // Detect invalid code points
+ test(char(255), 'B', "cast(char) 255 != 'B'");
+ test(wchar(0xD888), wchar('∑'), "cast(wchar) 55432 != '∑'");
+ test(dchar(0xDDDD), dchar('∑'), "cast(dchar) 56797 != '∑'");
+}
+
+void testToString()
+{
+ class Foo
+ {
+ this(string payload) {
+ this.payload = payload;
+ }
+
+ string payload;
+ override string toString() {
+ return "Foo(" ~ payload ~ ")";
+ }
+ }
+ test(new Foo("a"), new Foo("b"), "Foo(a) != Foo(b)");
+
+ scope f = cast(shared) new Foo("a");
+ if (!__ctfe) // Ref somehow get's lost in CTFE
+ test!"!="(f, f, "Foo(a) == Foo(a)");
+
+ // Verifiy that the const toString is selected if present
+ static struct Overloaded
+ {
+ string toString()
+ {
+ return "Mutable";
+ }
+
+ string toString() const
+ {
+ return "Const";
+ }
+ }
+
+ test!"!="(Overloaded(), Overloaded(), "Const == Const");
+
+ Foo fnull = null;
+ test!"!is"(fnull, fnull, "`null` is `null`");
+}
+
+
+void testArray()
+{
+ test([1], [0], "[1] != [0]");
+ test([1, 2, 3], [0], "[1, 2, 3] != [0]");
+
+ // test with long arrays
+ int[] arr;
+ foreach (i; 0 .. 100)
+ arr ~= i;
+ test(arr, [0], "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, ...] != [0]");
+
+ // Ignore fake arrays
+ static struct S
+ {
+ int[2] arr;
+ int[] get() return { return arr[]; }
+ alias get this;
+ }
+
+ const a = S([1, 2]);
+ test(a, S([3, 4]), "S([1, 2]) != S([3, 4])");
+}
+
+void testStruct()
+{
+ struct S { int s; }
+ struct T { T[] t; }
+ test(S(0), S(1), "S(0) != S(1)");
+ test(T([T(null)]), T(null), "T([T([])]) != T([])");
+
+ // https://issues.dlang.org/show_bug.cgi?id=20323
+ static struct NoCopy
+ {
+ @disable this(this);
+ }
+
+ NoCopy n;
+ test(_d_assert_fail!(typeof(n))("!=", n, n), "NoCopy() == NoCopy()");
+
+ shared NoCopy sn;
+ test(_d_assert_fail!(typeof(sn))("!=", sn, sn), "NoCopy() == NoCopy()");
+}
+
+void testAA()
+{
+ test([1:"one"], [2: "two"], `[1: "one"] != [2: "two"]`);
+ test!"in"(1, [2: 3], "1 !in [2: 3]");
+ test!"in"("foo", ["bar": true], `"foo" !in ["bar": true]`);
+}
+
+void testAttributes() @safe pure @nogc nothrow
+{
+ int a;
+ string s = _d_assert_fail!(int, char)("==", a, 'c', 1, 'd');
+ assert(s == `(0, 'c') != (1, 'd')`);
+
+ string s2 = _d_assert_fail!int("", a);
+ assert(s2 == `0 != true`);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20066
+void testVoidArray()
+{
+ test!"!is"([], null, (__ctfe ? "<void[] not supported>" : "[]") ~ " is `null`");
+ test!"!is"(null, null, "`null` is `null`");
+ test([1], null, "[1] != `null`");
+ test("s", null, "\"s\" != `null`");
+ test(['c'], null, "\"c\" != `null`");
+ test!"!="(null, null, "`null` == `null`");
+
+ const void[] chunk = [byte(1), byte(2), byte(3)];
+ test(chunk, null, (__ctfe ? "<void[] not supported>" : "[1, 2, 3]") ~ " != `null`");
+}
+
+void testTemporary()
+{
+ static struct Bad
+ {
+ ~this() @system {}
+ }
+
+ test!"!="(Bad(), Bad(), "Bad() == Bad()");
+}
+
+void testEnum()
+{
+ static struct UUID {
+ union
+ {
+ ubyte[] data = [1];
+ }
+ }
+
+ ubyte[] data;
+ enum ctfe = UUID();
+ test(_d_assert_fail!(ubyte[])("==", ctfe.data, data), "[1] != []");
+}
+
+void testUnary()
+{
+ test(_d_assert_fail!int("", 9), "9 != true");
+ test(_d_assert_fail!(int[])("!", [1, 2, 3]), "[1, 2, 3] == true");
+}
+
+void testTuple()
+{
+ test(_d_assert_fail("=="), "() != ()");
+ test(_d_assert_fail("!="), "() == ()");
+ test(_d_assert_fail(">="), "() < ()");
+}
+
+void testStructEquals()
+{
+ struct T {
+ bool b;
+ int i;
+ float f1 = 2.5;
+ float f2 = 0;
+ string s1 = "bar";
+ string s2;
+ }
+
+ T t1;
+ test!"!="(t1, t1, `T(false, 0, 2.5, 0, "bar", "") == T(false, 0, 2.5, 0, "bar", "")`);
+ T t2 = {s1: "bari"};
+ test(t1, t2, `T(false, 0, 2.5, 0, "bar", "") != T(false, 0, 2.5, 0, "bari", "")`);
+}
+
+void testStructEquals2()
+{
+ struct T {
+ bool b;
+ int i;
+ float f1 = 2.5;
+ float f2 = 0;
+ }
+
+ T t1;
+ test!"!="(t1, t1, `T(false, 0, 2.5, 0) == T(false, 0, 2.5, 0)`);
+ T t2 = {i: 2};
+ test(t1, t2, `T(false, 0, 2.5, 0) != T(false, 2, 2.5, 0)`);
+}
+
+void testStructEquals3()
+{
+ struct T {
+ bool b;
+ int i;
+ string s1 = "bar";
+ string s2;
+ }
+
+ T t1;
+ test!"!="(t1, t1, `T(false, 0, "bar", "") == T(false, 0, "bar", "")`);
+ T t2 = {s1: "bari"};
+ test(t1, t2, `T(false, 0, "bar", "") != T(false, 0, "bari", "")`);
+}
+
+void testStructEquals4()
+{
+ struct T {
+ float f1 = 2.5;
+ float f2 = 0;
+ string s1 = "bar";
+ string s2;
+ }
+
+ T t1;
+ test!"!="(t1, t1, `T(2.5, 0, "bar", "") == T(2.5, 0, "bar", "")`);
+ T t2 = {s1: "bari"};
+ test(t1, t2, `T(2.5, 0, "bar", "") != T(2.5, 0, "bari", "")`);
+}
+
+void testStructEquals5()
+{
+ struct T {
+ bool b;
+ int i;
+ float f2 = 0;
+ string s2;
+ }
+
+ T t1;
+ test!"!="(t1, t1, `T(false, 0, 0, "") == T(false, 0, 0, "")`);
+ T t2 = {b: true};
+ test(t1, t2, `T(false, 0, 0, "") != T(true, 0, 0, "")`);
+}
+
+void testStructEquals6()
+{
+ class C { override string toString() { return "C()"; }}
+ struct T {
+ bool b;
+ int i;
+ float f2 = 0;
+ string s2;
+ int[] arr;
+ C c;
+ }
+
+ T t1;
+ test!"!="(t1, t1, "T(false, 0, 0, \"\", [], `null`) == T(false, 0, 0, \"\", [], `null`)");
+ T t2 = {arr: [1]};
+ test(t1, t2, "T(false, 0, 0, \"\", [], `null`) != T(false, 0, 0, \"\", [1], `null`)");
+ T t3 = {c: new C()};
+ test(t1, t3, "T(false, 0, 0, \"\", [], `null`) != T(false, 0, 0, \"\", [], C())");
+}
+
+void testContextPointer()
+{
+ int i;
+ struct T
+ {
+ int j;
+ int get()
+ {
+ return i * j;
+ }
+ }
+ T t = T(1);
+ t.tupleof[$-1] = cast(void*) 0xABCD; // Deterministic context pointer
+ test(t, t, `T(1, <context>: 0xabcd) != T(1, <context>: 0xabcd)`);
+}
+
+void testExternClasses()
+{
+ {
+ extern(C++) static class Cpp
+ {
+ int a;
+ this(int a) { this.a = a; }
+ }
+ scope a = new Cpp(1);
+ scope b = new Cpp(2);
+ test(a, b, "Cpp(1) != Cpp(2)");
+ test(a, Cpp.init, "Cpp(1) != null");
+ }
+ {
+ extern(C++) static class CppToString
+ {
+ int a;
+ this(int a) { this.a = a; }
+ extern(D) string toString() const { return a == 0 ? "hello" : "world"; }
+ }
+ scope a = new CppToString(0);
+ scope b = new CppToString(1);
+ test(a, b, "hello != world");
+ }
+ if (!__ctfe)
+ {
+ extern(C++) static class Opaque;
+ Opaque null_ = null;
+ Opaque notNull = cast(Opaque) &null_;
+ test(null_, notNull, "null != <Opaque>");
+ }
+ {
+ extern(C++) static interface Stuff {}
+ scope Stuff stuff = new class Stuff {};
+ test(stuff, Stuff.init, "Stuff() != null");
+ }
+}
+
+void testShared()
+{
+ static struct Small
+ {
+ int i;
+ }
+
+ auto s1 = shared Small(1);
+ const s2 = shared Small(2);
+ test(s1, s2, "Small(1) != Small(2)");
+
+ static struct Big
+ {
+ long[10] l;
+ }
+
+ auto b1 = shared Big([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
+ const b2 = shared Big();
+ test(b1, b2, "Big([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) != Big([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])");
+
+ // Sanity check: Big shouldn't be supported by atomicLoad
+ import core.atomic : atomicLoad;
+ static assert( __traits(compiles, atomicLoad(s1)));
+ static assert(!__traits(compiles, atomicLoad(b1)));
+}
+
+void testException()
+{
+ static struct MayThrow
+ {
+ int i;
+ string toString()
+ {
+ if (i == 1)
+ throw new Exception("Error");
+ return "Some message";
+ }
+ }
+
+ test(MayThrow(0), MayThrow(1), `Some message != <toString() failed: "Error", called on MayThrow(1)>`);
+}
+
+void testOverlappingFields()
+{
+ static struct S
+ {
+ union
+ {
+ double num;
+ immutable(char)[] name;
+ }
+ }
+
+ test(S(1.0), S(2.0), "S(<overlapped field>, <overlapped field>) != S(<overlapped field>, <overlapped field>)");
+
+ static struct S2
+ {
+ int valid;
+ union
+ {
+ double num;
+ immutable(char)[] name;
+ }
+ }
+
+ test(S2(4, 1.0), S2(5, 2.0), "S2(4, <overlapped field>, <overlapped field>) != S2(5, <overlapped field>, <overlapped field>)");
+
+ static struct S3
+ {
+ union
+ {
+ double num;
+ immutable(char)[] name;
+ }
+ int valid;
+ }
+ S3 a = {
+ num: 1.0,
+ valid: 8
+ };
+
+ S3 b = {
+ num: 1.0,
+ valid: 8
+ };
+ test(a, b, "S3(<overlapped field>, <overlapped field>, 8) != S3(<overlapped field>, <overlapped field>, 8)");
+}
+
+void testDestruction()
+{
+ static class Test
+ {
+ __gshared string unary, binary;
+ __gshared bool run;
+
+ ~this()
+ {
+ run = true;
+ unary = _d_assert_fail!int("", 1);
+ binary = _d_assert_fail!int("==", 1, 2);
+ }
+ }
+
+ static void createGarbage()
+ {
+ new Test();
+ new long[100];
+ }
+
+ import core.memory : GC;
+ createGarbage();
+ GC.collect();
+
+ assert(Test.run);
+ assert(Test.unary == "Assertion failed (rich formatting is disabled in finalizers)");
+ assert(Test.binary == "Assertion failed (rich formatting is disabled in finalizers)");
+}
+
+int main()
+{
+ testIntegers();
+ testIntegerComparisons();
+ testFloatingPoint();
+ testPointers();
+ testStrings();
+ testToString();
+ testArray();
+ testStruct();
+ testAA();
+ testAttributes();
+ testVoidArray();
+ testTemporary();
+ testEnum();
+ testUnary();
+ testTuple();
+ if (!__ctfe)
+ testStructEquals();
+ if (!__ctfe)
+ testStructEquals2();
+ testStructEquals3();
+ if (!__ctfe)
+ testStructEquals4();
+ if (!__ctfe)
+ testStructEquals5();
+ if (!__ctfe)
+ testStructEquals6();
+ testContextPointer();
+ testExternClasses();
+ testShared();
+ testException();
+ testOverlappingFields();
+ if (!__ctfe)
+ testDestruction();
+
+ if (!__ctfe)
+ fprintf(stderr, "success.\n");
+ return 0;
+}
+
+enum forceCTFE = main();
diff --git a/libphobos/testsuite/libphobos.exceptions/catch_in_finally.d b/libphobos/testsuite/libphobos.exceptions/catch_in_finally.d
new file mode 100644
index 0000000..88bd739
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/catch_in_finally.d
@@ -0,0 +1,191 @@
+import core.stdc.stdio : fprintf, stderr;
+
+class MyException : Exception
+{
+ this() { super(typeof(this).stringof); }
+}
+
+void throw_catch()
+{
+ try
+ {
+ throw new MyException;
+ }
+ catch (MyException)
+ {
+ }
+ catch (Exception)
+ {
+ assert(false);
+ }
+}
+
+// Test that exceptions that are entirely thrown and caught in finally blocks don't affect exception handling.
+void test1()
+{
+ try
+ {
+ try
+ {
+ throw new Exception("p");
+ }
+ finally
+ {
+ throw_catch();
+ }
+ }
+ catch (Exception e)
+ {
+ assert(e.msg == "p");
+ }
+}
+
+// Test that exceptions that are entirely thrown and caught in finally blocks don't interfere with chaining.
+void test2()
+{
+ try
+ {
+ try
+ {
+ try
+ {
+ throw new Exception("p");
+ }
+ finally
+ {
+ throw new Exception("q");
+ }
+ }
+ finally
+ {
+ throw_catch();
+ }
+ }
+ catch(Exception e)
+ {
+ assert(e.msg == "p");
+ assert(e.next.msg == "q");
+ assert(!e.next.next);
+ }
+}
+
+void test3()
+{
+ try
+ {
+ try
+ {
+ try
+ {
+ throw new Exception("p");
+ }
+ finally
+ {
+ throw_catch();
+ }
+ }
+ finally
+ {
+ throw new Exception("q");
+ }
+ }
+ catch(Exception e)
+ {
+ assert(e.msg == "p");
+ assert(e.next.msg == "q");
+ assert(!e.next.next);
+ }
+}
+
+// Test order of exception handler operations.
+void test4()
+{
+ string result;
+ void throw_catch()
+ {
+ pragma(inline, false);
+ try
+ {
+ result ~= "b";
+ throw new MyException;
+ }
+ catch (MyException)
+ {
+ result ~= "c";
+ }
+ catch (Exception)
+ {
+ assert(false);
+ }
+ }
+ try
+ {
+ try
+ {
+ result ~= "a";
+ throw new Exception("");
+ }
+ finally
+ {
+ throw_catch();
+ }
+ }
+ catch(Exception e)
+ {
+ result ~= "d";
+ }
+ assert(result == "abcd");
+}
+
+void test5()
+{
+ string result;
+ void fail()
+ {
+ result ~= "b";
+ throw new Exception("a");
+ }
+
+ void throw_catch()
+ {
+ pragma(inline, false);
+ try
+ {
+ fail();
+ }
+ catch(Exception e)
+ {
+ assert(e.msg == "a");
+ assert(!e.next);
+ result ~= "c";
+ }
+ }
+ try
+ {
+ try
+ {
+ result ~= "a";
+ throw new Exception("x");
+ }
+ finally
+ {
+ throw_catch();
+ }
+ }
+ catch (Exception e)
+ {
+ assert(e.msg == "x");
+ assert(!e.next);
+ result ~= "d";
+ }
+ assert(result == "abcd");
+}
+
+void main() {
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+ fprintf(stderr, "success.\n");
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/future_message.d b/libphobos/testsuite/libphobos.exceptions/future_message.d
new file mode 100644
index 0000000..61b1034
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/future_message.d
@@ -0,0 +1,71 @@
+// { dg-options "-Wno-deprecated" }
+import core.stdc.stdio;
+
+// Make sure basic stuff works with future Throwable.message
+class NoMessage : Throwable
+{
+ @nogc @safe pure nothrow this(string msg, Throwable next = null)
+ {
+ super(msg, next);
+ }
+}
+
+class WithMessage : Throwable
+{
+ @nogc @safe pure nothrow this(string msg, Throwable next = null)
+ {
+ super(msg, next);
+ }
+
+ override const(char)[] message() const
+ {
+ return "I have a custom message.";
+ }
+}
+
+class WithMessageNoOverride : Throwable
+{
+ @nogc @safe pure nothrow this(string msg, Throwable next = null)
+ {
+ super(msg, next);
+ }
+
+ const(char)[] message() const
+ {
+ return "I have a custom message and no override.";
+ }
+}
+
+class WithMessageNoOverrideAndDifferentSignature : Throwable
+{
+ @nogc @safe pure nothrow this(string msg, Throwable next = null)
+ {
+ super(msg, next);
+ }
+
+ immutable(char)[] message()
+ {
+ return "I have a custom message and I'm nothing like Throwable.message.";
+ }
+}
+
+void test(Throwable t)
+{
+ try
+ {
+ throw t;
+ }
+ catch (Throwable e)
+ {
+ fprintf(stderr, "%.*s ", cast(int)e.message.length, e.message.ptr);
+ }
+}
+
+void main()
+{
+ test(new NoMessage("exception"));
+ test(new WithMessage("exception"));
+ test(new WithMessageNoOverride("exception"));
+ test(new WithMessageNoOverrideAndDifferentSignature("exception"));
+ fprintf(stderr, "\n");
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d b/libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d
new file mode 100644
index 0000000..3ff45e5
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/long_backtrace_trunc.d
@@ -0,0 +1,37 @@
+struct AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA(T) {
+struct BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB {
+struct CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC {
+struct DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD {
+struct EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE {
+struct FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF {
+struct GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG {
+struct HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH {
+ T tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt(int x) {
+ throw new Exception("test");
+ }
+}
+}
+}
+}
+}
+}
+}
+}
+
+void main() {
+ try {
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!int.
+ BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB.
+ CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC.
+ DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD.
+ EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE.
+ FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF.
+ GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG.
+ HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH x;
+ x.tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt(1);
+ } catch (Exception e) {
+ import core.stdc.stdio;
+ auto str = e.toString();
+ printf("%.*s\n", cast(int)str.length, str.ptr);
+ }
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/refcounted.d b/libphobos/testsuite/libphobos.exceptions/refcounted.d
new file mode 100644
index 0000000..2b7e79b
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/refcounted.d
@@ -0,0 +1,96 @@
+// { dg-options "-fpreview=dip1008" }
+class E : Exception
+{
+ static int instances;
+ this(string msg = "")
+ {
+ super(msg);
+ instances++;
+ }
+
+ ~this()
+ {
+ instances--;
+ }
+}
+
+void main()
+{
+ alias chain = Exception.chainTogether;
+
+ assert(chain(null, null) is null);
+
+ try
+ {
+ throw new E();
+ }
+ catch (E e)
+ {
+ assert(E.instances == 1);
+ assert(e.refcount == 2);
+ }
+
+ assert(E.instances == 0);
+
+ try
+ {
+ throw new E();
+ }
+ catch (E e)
+ {
+ assert(chain(null, e) is e);
+ assert(e.refcount == 2); // "Owned by e" + 1
+ }
+
+ assert(E.instances == 0);
+
+ try
+ {
+ throw new E();
+ }
+ catch (E e)
+ {
+ assert(chain(e, null) is e);
+ assert(e.refcount == 2); // "Owned by e" + 1
+ }
+
+ assert(E.instances == 0);
+
+ try
+ {
+ throw new E("first");
+ }
+ catch (E first)
+ {
+ try
+ {
+ throw new E("second");
+ }
+ catch (E second)
+ {
+ try
+ {
+ throw new E("third");
+ }
+ catch (E third)
+ {
+ assert(chain(first, second) is first);
+ assert(first.next is second);
+ assert(second.next is null);
+
+ assert(chain(first, third) is first);
+ assert(first.next is second);
+ assert(second.next is third);
+ assert(third.next is null);
+
+ assert(first.refcount == 2);
+ assert(second.refcount == 3);
+ assert(third.refcount == 3);
+ }
+ }
+
+ assert(E.instances == 3);
+ }
+
+ assert(E.instances == 0);
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d
new file mode 100644
index 0000000..bd0c227
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions.d
@@ -0,0 +1,15 @@
+// { dg-shouldfail "uncaught exception" }
+// { dg-output "gcc.deh.*: uncaught exception" }
+// Code adapted from
+// http://arsdnet.net/this-week-in-d/2016-aug-07.html
+extern extern(C) __gshared bool rt_trapExceptions;
+extern extern(C) int _d_run_main(int, char**, void*) @system;
+
+extern(C) int main(int argc, char** argv) {
+ rt_trapExceptions = false;
+ return _d_run_main(argc, argv, &_main);
+}
+
+int _main() {
+ throw new Exception("this will abort");
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d
new file mode 100644
index 0000000..fc4448c
--- /dev/null
+++ b/libphobos/testsuite/libphobos.exceptions/rt_trap_exceptions_drt.d
@@ -0,0 +1,11 @@
+// { dg-shouldfail "uncaught exception" }
+void test()
+{
+ int innerLocal = 20;
+ throw new Exception("foo");
+}
+void main(string[] args)
+{
+ string myLocal = "bar";
+ test();
+}
diff --git a/libphobos/testsuite/libphobos.exceptions/unknown_gc.d b/libphobos/testsuite/libphobos.exceptions/unknown_gc.d
index eb95aee..183c0f2 100644
--- a/libphobos/testsuite/libphobos.exceptions/unknown_gc.d
+++ b/libphobos/testsuite/libphobos.exceptions/unknown_gc.d
@@ -2,8 +2,12 @@
// { dg-options "-shared-libphobos" }
// { dg-shouldfail "unknowngc" }
// { dg-output "No GC was initialized, please recheck the name of the selected GC \\('unknowngc'\\)." }
+import core.memory;
+
extern(C) __gshared string[] rt_options = [ "gcopt=gc:unknowngc" ];
void main()
{
+ // GC initialized upon first call -> Unknown GC error is thrown
+ GC.enable();
}
diff --git a/libphobos/testsuite/libphobos.gc/attributes.d b/libphobos/testsuite/libphobos.gc/attributes.d
new file mode 100644
index 0000000..a7acd6c
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/attributes.d
@@ -0,0 +1,30 @@
+import core.memory;
+
+// TODO: The following should work, but L10 (second assert) fails.
+version(none) void dotest(T) (T* ptr)
+{
+ GC.clrAttr(ptr, uint.max);
+ assert(GC.getAttr(ptr) == 0);
+
+ GC.setAttr(ptr, GC.BlkAttr.NO_MOVE);
+ assert(GC.getAttr(ptr) == GC.BlkAttr.NO_MOVE);
+
+ GC.clrAttr(ptr, GC.BlkAttr.NO_MOVE);
+ assert(GC.getAttr(ptr) == 0);
+ GC.clrAttr(ptr, GC.BlkAttr.NO_MOVE);
+ assert(GC.getAttr(ptr) == 0);
+}
+else void dotest(T) (T* ptr)
+{
+ // https://issues.dlang.org/show_bug.cgi?id=21484
+ GC.clrAttr(ptr, uint.max);
+ GC.setAttr(ptr, GC.BlkAttr.NO_MOVE);
+ GC.getAttr(ptr);
+}
+
+void main ()
+{
+ auto ptr = new int;
+ dotest!(const(int))(ptr);
+ dotest!(int)(ptr);
+}
diff --git a/libphobos/testsuite/libphobos.gc/forkgc.d b/libphobos/testsuite/libphobos.gc/forkgc.d
new file mode 100644
index 0000000..9c18dc2
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/forkgc.d
@@ -0,0 +1,36 @@
+import core.memory;
+import core.stdc.stdio;
+import core.sys.posix.sys.wait;
+import core.sys.posix.unistd;
+
+void main()
+{
+ printf("[parent] Creating garbage...\n");
+ foreach (n; 0 .. 1_000)
+ new uint[10_000];
+ printf("[parent] Collecting garbage...\n");
+ GC.collect();
+ printf("[parent] Forking...\n");
+ auto i = fork();
+ if (i < 0)
+ assert(false, "Fork failed");
+ if (i == 0)
+ {
+ printf("[child] In fork.\n");
+ printf("[child] Creating garbage...\n");
+ foreach (n; 0 .. 1_000)
+ new uint[10_000];
+ printf("[child] Collecting garbage...\n");
+ GC.collect();
+ printf("[child] Exiting fork.\n");
+ }
+ else
+ {
+ printf("[parent] Waiting for fork (PID %d).\n", i);
+ int status;
+ i = waitpid(i, &status, 0);
+ printf("[parent] Fork %d exited (%d).\n", i, status);
+ if (status != 0)
+ assert(false, "child had errors");
+ }
+}
diff --git a/libphobos/testsuite/libphobos.gc/forkgc2.d b/libphobos/testsuite/libphobos.gc/forkgc2.d
new file mode 100644
index 0000000..de7796c
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/forkgc2.d
@@ -0,0 +1,22 @@
+import core.stdc.stdlib : exit;
+import core.sys.posix.sys.wait : waitpid;
+import core.sys.posix.unistd : fork;
+import core.thread : Thread;
+
+void main()
+{
+ foreach (t; 0 .. 10)
+ new Thread({
+ foreach (n; 0 .. 100)
+ {
+ foreach (x; 0 .. 100)
+ new ubyte[x];
+ auto f = fork();
+ assert(f >= 0);
+ if (f == 0)
+ exit(0);
+ else
+ waitpid(f, null, 0);
+ }
+ }).start();
+}
diff --git a/libphobos/testsuite/libphobos.gc/gc.exp b/libphobos/testsuite/libphobos.gc/gc.exp
new file mode 100644
index 0000000..cb78538
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/gc.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.d]]
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_DFLAGS
+
+# All done.
+dg-finish
diff --git a/libphobos/testsuite/libphobos.gc/nocollect.d b/libphobos/testsuite/libphobos.gc/nocollect.d
new file mode 100644
index 0000000..5df1483
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/nocollect.d
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=20567
+
+import core.memory;
+
+void main()
+{
+ auto stats = GC.profileStats();
+ assert(stats.numCollections == 0);
+
+ char[] sbuf = new char[256]; // small pool
+ char[] lbuf = new char[2049]; // large pool
+
+ stats = GC.profileStats();
+ assert(stats.numCollections == 0);
+} \ No newline at end of file
diff --git a/libphobos/testsuite/libphobos.gc/precisegc.d b/libphobos/testsuite/libphobos.gc/precisegc.d
new file mode 100644
index 0000000..9bcaf3f
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/precisegc.d
@@ -0,0 +1,126 @@
+// precise GC related:
+// https://issues.dlang.org/show_bug.cgi?id=3463
+// https://issues.dlang.org/show_bug.cgi?id=4358
+// https://issues.dlang.org/show_bug.cgi?id=9094
+// https://issues.dlang.org/show_bug.cgi?id=13801
+// https://issues.dlang.org/show_bug.cgi?id=18900
+module testgc;
+
+import core.memory;
+import core.stdc.stdio;
+
+class C
+{
+ __gshared int dtors;
+ ~this() { dtors++; }
+
+ C next;
+ size_t val;
+}
+
+struct S
+{
+ __gshared int dtors;
+ ~this() { dtors++; }
+
+ size_t val;
+ S* next;
+}
+
+struct L
+{
+ __gshared int dtors;
+ ~this() { dtors++; }
+
+ size_t[1000] data;
+ S* node;
+}
+
+struct Roots
+{
+ C c;
+ S *s;
+ L *l;
+};
+
+Roots* roots;
+size_t iroots;
+
+void init()
+{
+ roots = new Roots;
+ roots.c = new C;
+ roots.c.next = new C;
+
+ roots.s = new S;
+ roots.s.next = new S;
+
+ roots.l = new L;
+ roots.l.node = new S;
+}
+
+void verifyPointers()
+{
+ assert(C.dtors == 0);
+ assert(S.dtors == 0);
+ assert(L.dtors == 0);
+}
+
+// compiling with -gx should help eliminating false pointers on the stack
+Roots makeFalsePointers()
+{
+ roots.c.val = cast(size_t) cast(void*) roots.c.next;
+ roots.c.next = null;
+ roots.s.val = cast(size_t) cast(void*) roots.s.next;
+ roots.s.next = null;
+ roots.l.data[7] = cast(size_t) cast(void*) roots.l.node;
+ roots.l.node = null;
+
+ return Roots(null, null, null); // try to spill register contents
+}
+
+Roots moveRoot()
+{
+ iroots = cast(size_t)roots;
+ roots = null;
+
+ return Roots(null, null, null); // try to spill register contents
+}
+
+// compiling with -gx should help eliminating false pointers on the stack
+void verifyFalsePointers()
+{
+ assert(C.dtors <= 1);
+ if (C.dtors < 1) printf ("False pointers? C.dtors = %d, 1 expected\n", C.dtors);
+ assert(S.dtors <= 2);
+ if (S.dtors < 2) printf ("False pointers? S.dtors = %d, 2 expected\n", S.dtors);
+ assert(L.dtors == 0);
+}
+
+extern(C) __gshared string[] rt_options = [ "gcopt=gc:precise", "scanDataSeg=precise" ];
+
+void main()
+{
+ GC.collect(); // cleanup from unittests
+
+ init();
+ GC.collect(); // should collect nothing
+ verifyPointers();
+
+ makeFalsePointers();
+ GC.collect(); // should collect roots.c.next, roots.s.next and roots.l.node
+ verifyFalsePointers();
+
+ moveRoot();
+ GC.collect(); // should collect all
+
+ version(Windows) // precise DATA scanning only implemented on Windows
+ {
+ assert(C.dtors <= 2);
+ if (C.dtors < 2) printf ("False DATA pointers? C.dtors = %d, 2 expected\n", C.dtors);
+ assert(S.dtors <= 3);
+ if (S.dtors < 3) printf ("False DATA pointers? S.dtors = %d, 2 expected\n", S.dtors);
+ assert(L.dtors <= 1);
+ if (L.dtors < 1) printf ("False DATA pointers? L.dtors = %d, 1 expected\n", L.dtors);
+ }
+}
diff --git a/libphobos/testsuite/libphobos.gc/recoverfree.d b/libphobos/testsuite/libphobos.gc/recoverfree.d
new file mode 100644
index 0000000..59c3b4a
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/recoverfree.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=20438
+import core.stdc.stdio;
+import core.memory;
+
+void main()
+{
+ auto used0 = GC.stats.usedSize;
+ void* z = GC.malloc(100);
+ GC.free(z);
+ GC.collect();
+ auto used1 = GC.stats.usedSize;
+ used1 <= used0 || assert(false);
+}
diff --git a/libphobos/testsuite/libphobos.gc/sigmaskgc.d b/libphobos/testsuite/libphobos.gc/sigmaskgc.d
new file mode 100644
index 0000000..eb46316
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/sigmaskgc.d
@@ -0,0 +1,42 @@
+
+// https://issues.dlang.org/show_bug.cgi?id=20256
+
+extern(C) __gshared string[] rt_options = [ "gcopt=parallel:1" ];
+
+void main()
+{
+ version (Posix)
+ {
+ import core.sys.posix.signal;
+ import core.sys.posix.unistd;
+ import core.thread;
+ import core.memory;
+
+ sigset_t m;
+ sigemptyset(&m);
+ sigaddset(&m, SIGHUP);
+
+ auto x = new int[](10000);
+ foreach (i; 0 .. 10000)
+ {
+ x ~= i;
+ }
+ GC.collect(); // GC create thread
+
+ sigprocmask(SIG_BLOCK, &m, null); // block SIGHUP from delivery to main thread
+
+ auto parent_pid = getpid();
+ auto child_pid = fork();
+ assert(child_pid >= 0);
+ if (child_pid == 0)
+ {
+ kill(parent_pid, SIGHUP); // send signal to parent
+ _exit(0);
+ }
+ // parent
+ Thread.sleep(100.msecs);
+ // if we are here, then GC threads didn't receive SIGHUP,
+ // otherwise whole process killed
+ _exit(0);
+ }
+}
diff --git a/libphobos/testsuite/libphobos.gc/startbackgc.d b/libphobos/testsuite/libphobos.gc/startbackgc.d
new file mode 100644
index 0000000..bf51fbd
--- /dev/null
+++ b/libphobos/testsuite/libphobos.gc/startbackgc.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=20270
+import core.sys.posix.sys.wait : waitpid;
+import core.sys.posix.unistd : fork, _exit;
+import core.thread : Thread;
+
+void main()
+{
+ foreach (t; 0 .. 10)
+ new Thread({
+ foreach (n; 0 .. 100)
+ {
+ foreach (x; 0 .. 100)
+ new ubyte[x];
+ auto f = fork();
+ assert(f >= 0);
+ if (f == 0)
+ _exit(0);
+ else
+ waitpid(f, null, 0);
+ }
+ }).start();
+}
diff --git a/libphobos/testsuite/libphobos.hash/test_hash.d b/libphobos/testsuite/libphobos.hash/test_hash.d
index b406266..d0a8e5fb 100644
--- a/libphobos/testsuite/libphobos.hash/test_hash.d
+++ b/libphobos/testsuite/libphobos.hash/test_hash.d
@@ -1,3 +1,5 @@
+// { dg-prune-output "Warning: struct HasNonConstToHash has method toHash" }
+// { dg-prune-output "HasNonConstToHash.toHash defined here:" }
void main()
{
issue19562();
@@ -8,8 +10,14 @@ void main()
issue19005();
issue19204();
issue19262();
+ issue19282();
+ issue19332(); // Support might be removed in the future!
issue19568();
issue19582();
+ issue20034();
+ issue21642();
+ issue22024();
+ issue22076();
testTypeInfoArrayGetHash1();
testTypeInfoArrayGetHash2();
pr2243();
@@ -130,6 +138,30 @@ void issue19262() nothrow
h = hashOf(aa, h);
}
+extern(C++) class Issue19282CppClass {}
+
+/// test that hashOf doesn't crash for non-null C++ objects.
+void issue19282()
+{
+ Issue19282CppClass c = new Issue19282CppClass();
+ size_t h = hashOf(c);
+ h = hashOf(c, h);
+}
+
+/// Ensure hashOf works for const struct that has non-const toHash & has all
+/// fields bitwise-hashable. (Support might be removed in the future!)
+void issue19332()
+{
+ static struct HasNonConstToHash
+ {
+ int a;
+ size_t toHash() { return a; }
+ }
+ const HasNonConstToHash val;
+ size_t h = hashOf(val);
+ h = hashOf!(const HasNonConstToHash)(val); // Ensure doesn't match more than one overload.
+}
+
/// hashOf should not unnecessarily call a struct's fields' postblits & dtors in CTFE
void issue19568()
{
@@ -189,11 +221,99 @@ void issue19582()
}
}
enum b2 = () {
- S[10] a;
- return ((const S[] a) @nogc nothrow pure @safe => toUbyte(a))(a);
+ return ((const S[] a) @nogc nothrow pure @safe => toUbyte(a))(new S[10]);
}();
}
+/// Check core.internal.hash.hashOf works with enums of non-scalar values
+void issue20034()
+{
+ enum E
+ {
+ a = "foo"
+ }
+ // should compile
+ assert(hashOf(E.a, 1));
+}
+
+/// [REG 2.084] hashOf will fail to compile for some structs/unions that recursively contain shared enums
+void issue21642() @safe nothrow pure
+{
+ enum C : char { _ = 1, }
+ union U { C c; void[0] _; }
+ shared union V { U u; }
+ cast(void) hashOf(V.init);
+ // Also test the underlying reason the above was failing.
+ import core.internal.convert : toUbyte;
+ shared C c;
+ assert(toUbyte(c) == [ubyte(1)]);
+}
+
+/// Accept enum type whose ultimate base type is a SIMD vector.
+void issue22024() @nogc nothrow pure @safe
+{
+ static if (is(__vector(float[2])))
+ {
+ enum E2 : __vector(float[2]) { a = __vector(float[2]).init, }
+ enum F2 : E2 { a = E2.init, }
+ assert(hashOf(E2.init) == hashOf(F2.init));
+ assert(hashOf(E2.init, 1) == hashOf(F2.init, 1));
+ }
+ static if (is(__vector(float[4])))
+ {
+ enum E4 : __vector(float[4]) { a = __vector(float[4]).init, }
+ enum F4 : E4 { a = E4.init, }
+ assert(hashOf(E4.init) == hashOf(F4.init));
+ assert(hashOf(E4.init, 1) == hashOf(F4.init, 1));
+ }
+}
+
+/// hashOf(S) can segfault if S.toHash is forwarded via `alias this` to a
+/// receiver which may be null.
+void issue22076()
+{
+ static struct S0 { Object a; alias a this; }
+
+ static struct S1
+ {
+ S0 a;
+ inout(S0)* b() inout nothrow { return &a; }
+ alias b this;
+ }
+
+ static struct S2
+ {
+ S0 a;
+ S1 b;
+ }
+
+ extern(C++) static class C0
+ {
+ int foo() { return 0; } // Need at least one function in vtable.
+ S0 a; alias a this;
+ }
+
+ extern(C++) static class C1
+ {
+ S1 a;
+ inout(S1)* b() inout nothrow { return &a; }
+ alias b this;
+ }
+
+ cast(void) hashOf(S0.init);
+ cast(void) hashOf(S0.init, 0);
+ cast(void) hashOf(S1.init);
+ cast(void) hashOf(S1.init, 0);
+ cast(void) hashOf(S2.init);
+ cast(void) hashOf(S2.init, 0);
+ auto c0 = new C0();
+ cast(void) hashOf(c0);
+ cast(void) hashOf(c0, 0);
+ auto c1 = new C1();
+ cast(void) hashOf(c1);
+ cast(void) hashOf(c1, 0);
+}
+
/// Tests ensure TypeInfo_Array.getHash uses element hash functions instead
/// of hashing array data.
void testTypeInfoArrayGetHash1()
@@ -300,11 +420,9 @@ void pr2243()
enum Bar vsexpr = Bar();
enum int[int] aaexpr = [99:2, 12:6, 45:4];
enum Gun eexpr = Gun.A;
- enum cdouble cexpr = 7+4i;
enum Foo[] staexpr = [Foo(), Foo(), Foo()];
enum Bar[] vsaexpr = [Bar(), Bar(), Bar()];
enum realexpr = 7.88;
- enum raexpr = [8.99L+86i, 3.12L+99i, 5.66L+12i];
enum nullexpr = null;
enum plstr = Plain();
enum plarrstr = [Plain(), Plain(), Plain()];
@@ -328,7 +446,6 @@ void pr2243()
enum h10 = vsexpr.hashOf();
enum h11 = aaexpr.hashOf();
enum h12 = eexpr.hashOf();
- enum h13 = cexpr.hashOf();
enum h14 = hashOf(new Boo);
enum h15 = staexpr.hashOf();
enum h16 = hashOf([new Boo, new Boo, new Boo]);
@@ -349,7 +466,6 @@ void pr2243()
auto h27 = ptrexpr.hashOf();
enum h28 = realexpr.hashOf();
- enum h29 = raexpr.hashOf();
enum h30 = nullexpr.hashOf();
enum h31 = plstr.hashOf();
enum h32 = plarrstr.hashOf();
@@ -367,7 +483,6 @@ void pr2243()
auto v10 = vsexpr;
auto v11 = aaexpr;
auto v12 = eexpr;
- auto v13 = cexpr;
auto v14 = new Boo;
auto v15 = staexpr;
auto v16 = [new Boo, new Boo, new Boo];
@@ -389,7 +504,6 @@ void pr2243()
auto v26 = dgexpr;
auto v27 = ptrexpr;
auto v28 = realexpr;
- auto v29 = raexpr;
//runtime hashes
auto rth1 = hashOf(v1);
@@ -404,7 +518,6 @@ void pr2243()
auto rth10 = hashOf(v10);
auto rth11 = hashOf(v11);
auto rth12 = hashOf(v12);
- auto rth13 = hashOf(v13);
auto rth14 = hashOf(v14);
auto rth15 = hashOf(v15);
auto rth16 = hashOf(v16);
@@ -422,7 +535,6 @@ void pr2243()
auto rth26 = hashOf(v26);
auto rth27 = hashOf(v27);
auto rth28 = hashOf(v28);
- auto rth29 = hashOf(v29);
auto rth31 = hashOf(v31);
auto rth32 = hashOf(v32);
@@ -440,7 +552,6 @@ void pr2243()
assert(h10 == rth10);
assert(h11 == rth11);
assert(h12 == rth12);
- assert(h13 == rth13);
assert(h14 == rth14);
assert(h15 == rth15);
assert(h16 == rth16);
@@ -455,8 +566,7 @@ void pr2243()
assert(h25 == rth25);
assert(h26 == rth26);
assert(h27 == rth27);
- assert(h28 == rth28);
- assert(h29 == rth29);*/
+ assert(h28 == rth28);*/
assert(h30 == rth30);
assert(h31 == rth31);
assert(h32 == rth32);
@@ -482,7 +592,6 @@ void pr2243()
auto tih10 = tiHashOf(v10);
auto tih11 = tiHashOf(v11);
auto tih12 = tiHashOf(v12);
- auto tih13 = tiHashOf(v13);
auto tih14 = tiHashOf(v14);
auto tih15 = tiHashOf(v15);
auto tih16 = tiHashOf(v16);
@@ -498,7 +607,6 @@ void pr2243()
auto tih26 = tiHashOf(v26);
auto tih27 = tiHashOf(v27);
auto tih28 = tiHashOf(v28);
- auto tih29 = tiHashOf(v29);
auto tih30 = tiHashOf(v30);
auto tih31 = tiHashOf(v31);
auto tih32 = tiHashOf(v32);
@@ -516,7 +624,6 @@ void pr2243()
//assert(tih10 == rth10); // need compiler-generated __xtoHash changes
assert(tih11 == rth11);
assert(tih12 == rth12);
- assert(tih13 == rth13);
assert(tih14 == rth14);
assert(tih15 == rth15);
assert(tih16 == rth16);
@@ -532,7 +639,6 @@ void pr2243()
assert(tih26 == rth26);
assert(tih27 == rth27);
assert(tih28 == rth28);
- assert(tih29 == rth29);
assert(tih30 == rth30);
assert(tih31 == rth31);
assert(tih32 == rth32);
diff --git a/libphobos/testsuite/libphobos.imports/bug18193.d b/libphobos/testsuite/libphobos.imports/bug18193.d
new file mode 100644
index 0000000..fc8f5ca
--- /dev/null
+++ b/libphobos/testsuite/libphobos.imports/bug18193.d
@@ -0,0 +1,4 @@
+// { dg-options "-fversion=Shared" }
+// { dg-do compile }
+import core.runtime;
+import core.thread;
diff --git a/libphobos/testsuite/libphobos.imports/imports.exp b/libphobos/testsuite/libphobos.imports/imports.exp
new file mode 100644
index 0000000..344e415
--- /dev/null
+++ b/libphobos/testsuite/libphobos.imports/imports.exp
@@ -0,0 +1,29 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib libphobos-dg.exp
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.d]]
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_DFLAGS
+
+# All done.
+dg-finish
diff --git a/libphobos/testsuite/libphobos.init_fini/custom_gc.d b/libphobos/testsuite/libphobos.init_fini/custom_gc.d
new file mode 100644
index 0000000..a5e2bf4
--- /dev/null
+++ b/libphobos/testsuite/libphobos.init_fini/custom_gc.d
@@ -0,0 +1,203 @@
+import core.gc.registry;
+import core.gc.gcinterface;
+import core.stdc.stdlib;
+
+static import core.memory;
+
+extern (C) __gshared string[] rt_options = ["gcopt=gc:malloc"];
+
+extern (C) pragma(crt_constructor) void register_mygc()
+{
+ registerGCFactory("malloc", &MallocGC.initialize);
+}
+
+extern (C) void register_default_gcs()
+{
+ // remove default GCs
+}
+
+/** Simple GC that requires any pointers passed to it's API
+ to point to start of the allocation.
+ */
+class MallocGC : GC
+{
+nothrow @nogc:
+ static GC initialize()
+ {
+ import core.stdc.string : memcpy;
+
+ __gshared ubyte[__traits(classInstanceSize, MallocGC)] buf;
+
+ auto init = typeid(MallocGC).initializer();
+ assert(init.length == buf.length);
+ auto instance = cast(MallocGC) memcpy(buf.ptr, init.ptr, init.length);
+ instance.__ctor();
+ return instance;
+ }
+
+ this()
+ {
+ }
+
+ void Dtor()
+ {
+ }
+
+ void enable()
+ {
+ }
+
+ void disable()
+ {
+ }
+
+ void collect() nothrow
+ {
+ }
+
+ void collectNoStack() nothrow
+ {
+ }
+
+ void minimize() nothrow
+ {
+ }
+
+ uint getAttr(void* p) nothrow
+ {
+ return 0;
+ }
+
+ uint setAttr(void* p, uint mask) nothrow
+ {
+ return mask;
+ }
+
+ uint clrAttr(void* p, uint mask) nothrow
+ {
+ return mask;
+ }
+
+ void* malloc(size_t size, uint bits, const TypeInfo ti) nothrow
+ {
+ return sentinelAdd(.malloc(size + sentinelSize), size);
+ }
+
+ BlkInfo qalloc(size_t size, uint bits, const scope TypeInfo ti) nothrow
+ {
+ return BlkInfo(malloc(size, bits, ti), size);
+ }
+
+ void* calloc(size_t size, uint bits, const TypeInfo ti) nothrow
+ {
+ return sentinelAdd(.calloc(1, size + sentinelSize), size);
+ }
+
+ void* realloc(void* p, size_t size, uint bits, const TypeInfo ti) nothrow
+ {
+ return sentinelAdd(.realloc(p - sentinelSize, size + sentinelSize), size);
+ }
+
+ size_t extend(void* p, size_t minsize, size_t maxsize, const TypeInfo ti) nothrow
+ {
+ return 0;
+ }
+
+ size_t reserve(size_t size) nothrow
+ {
+ return 0;
+ }
+
+ void free(void* p) nothrow
+ {
+ free(p - sentinelSize);
+ }
+
+ void* addrOf(void* p) nothrow
+ {
+ return p;
+ }
+
+ size_t sizeOf(void* p) nothrow
+ {
+ return query(p).size;
+ }
+
+ BlkInfo query(void* p) nothrow
+ {
+ return p ? BlkInfo(p, sentinelGet(p)) : BlkInfo.init;
+ }
+
+ core.memory.GC.Stats stats() nothrow
+ {
+ return core.memory.GC.Stats.init;
+ }
+
+ core.memory.GC.ProfileStats profileStats() nothrow
+ {
+ return typeof(return).init;
+ }
+
+ void addRoot(void* p) nothrow @nogc
+ {
+ }
+
+ void removeRoot(void* p) nothrow @nogc
+ {
+ }
+
+ @property RootIterator rootIter() @nogc
+ {
+ return null;
+ }
+
+ void addRange(void* p, size_t sz, const TypeInfo ti) nothrow @nogc
+ {
+ }
+
+ void removeRange(void* p) nothrow @nogc
+ {
+ }
+
+ @property RangeIterator rangeIter() @nogc
+ {
+ return null;
+ }
+
+ void runFinalizers(const scope void[] segment) nothrow
+ {
+ }
+
+ bool inFinalizer() nothrow
+ {
+ return false;
+ }
+
+ ulong allocatedInCurrentThread() nothrow
+ {
+ return stats().allocatedInCurrentThread;
+ }
+
+private:
+ // doesn't care for alignment
+ static void* sentinelAdd(void* p, size_t value)
+ {
+ *cast(size_t*) p = value;
+ return p + sentinelSize;
+ }
+
+ static size_t sentinelGet(void* p)
+ {
+ return *cast(size_t*)(p - sentinelSize);
+ }
+
+ enum sentinelSize = size_t.sizeof;
+}
+
+void main()
+{
+ // test array append cache
+ char[] s;
+ foreach (char c; char.min .. char.max + 1)
+ s ~= c;
+}
diff --git a/libphobos/testsuite/libphobos.init_fini/test18996.d b/libphobos/testsuite/libphobos.init_fini/test18996.d
new file mode 100644
index 0000000..01d514c
--- /dev/null
+++ b/libphobos/testsuite/libphobos.init_fini/test18996.d
@@ -0,0 +1,13 @@
+// Issue https://issues.dlang.org/show_bug.cgi?id=18996
+// Array!string calls removeRange without first adding the range, but never
+// initializes the GC. The behavior of the default GC is to ignore removing
+// ranges when the range wasn't added. The ProtoGC originally would crash when
+// this happened.
+
+import core.memory;
+
+void main()
+{
+ GC.removeRange(null);
+ GC.removeRoot(null);
+}
diff --git a/libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d b/libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d
new file mode 100644
index 0000000..bc0695e
--- /dev/null
+++ b/libphobos/testsuite/libphobos.lifetime/large_aggregate_destroy_21097.d
@@ -0,0 +1,78 @@
+// https://issues.dlang.org/show_bug.cgi?id=21097
+
+// The crucial part of the test cases is testing `destroy`. At the same time, we test
+// `core.internal.lifetime.emplaceInitializer` (which is currently called by `destroy`).
+
+enum SIZE = 10_000_000; // 10 MB should exhaust the stack on most if not all test systems.
+
+import core.internal.lifetime;
+
+void test_largestruct()
+{
+ static struct LargeStruct
+ {
+ int[SIZE/2] a1;
+ int b = 42;
+ int[SIZE/2] a2;
+ }
+ static LargeStruct s = void;
+ emplaceInitializer(s);
+ assert(s.b == 42);
+ s.b = 101;
+ destroy(s);
+ assert(s.b == 42);
+}
+
+void test_largestruct_w_opassign()
+{
+ static struct LargeStructOpAssign
+ {
+ int[SIZE/2] a1;
+ int b = 420; // non-zero init
+ int[SIZE/2] a2;
+
+ void opAssign(typeof(this)) {} // hasElaborateAssign == true
+ }
+ static LargeStructOpAssign s = void;
+ emplaceInitializer(s);
+ assert(s.b == 420);
+ s.b = 101;
+ destroy(s);
+ assert(s.b == 420);
+}
+
+void test_largearray() {
+ static struct NonZero
+ {
+ int i = 123;
+ }
+ static NonZero[SIZE] s = void;
+ emplaceInitializer(s);
+ assert(s[SIZE/2] == NonZero.init);
+ s[10] = NonZero(101);
+ destroy(s);
+ assert(s[10] == NonZero.init);
+}
+
+void test_largearray_w_opassign() {
+ static struct NonZeroWithOpAssign
+ {
+ int i = 123;
+ void opAssign(typeof(this)) {} // hasElaborateAssign == true
+ }
+ static NonZeroWithOpAssign[SIZE] s = void;
+ emplaceInitializer(s);
+ assert(s[SIZE/2] == NonZeroWithOpAssign.init);
+ s[10] = NonZeroWithOpAssign(101);
+ destroy(s);
+ assert(s[10] == NonZeroWithOpAssign.init);
+}
+
+int main()
+{
+ test_largestruct();
+ test_largestruct_w_opassign();
+ test_largearray();
+ test_largearray_w_opassign();
+ return 0;
+}
diff --git a/libphobos/testsuite/libphobos.lifetime/lifetime.exp b/libphobos/testsuite/libphobos.lifetime/lifetime.exp
new file mode 100644
index 0000000..cb78538
--- /dev/null
+++ b/libphobos/testsuite/libphobos.lifetime/lifetime.exp
@@ -0,0 +1,27 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.d]]
+
+# Main loop.
+dg-runtest $tests "" $DEFAULT_DFLAGS
+
+# All done.
+dg-finish
diff --git a/libphobos/testsuite/libphobos.phobos/phobos.exp b/libphobos/testsuite/libphobos.phobos/phobos.exp
index 937849e..84e9898 100644
--- a/libphobos/testsuite/libphobos.phobos/phobos.exp
+++ b/libphobos/testsuite/libphobos.phobos/phobos.exp
@@ -27,7 +27,7 @@ if { ![is-effective-target d_runtime_has_std_library] } {
# Gather a list of all tests.
set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]]
-set version_flags ""
+set version_flags "-fversion=StdUnittest"
if { [is-effective-target linux_pre_2639] } {
lappend version_flags "-fversion=Linux_Pre_2639"
diff --git a/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp b/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp
index 8498522..b8f8e42 100644
--- a/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp
+++ b/libphobos/testsuite/libphobos.phobos_shared/phobos_shared.exp
@@ -27,7 +27,7 @@ if { ![is-effective-target d_runtime_has_std_library] } {
# Gather a list of all tests.
set tests [lsort [filter_libphobos_unittests [find $srcdir/../src "*.d"]]]
-set version_flags ""
+set version_flags "-fversion=StdUnittest"
if { [is-effective-target linux_pre_2639] } {
lappend version_flags "-fversion=Linux_Pre_2639"
diff --git a/libphobos/testsuite/libphobos.shared/host.c b/libphobos/testsuite/libphobos.shared/host.c
index 81e896a..395ad0c 100644
--- a/libphobos/testsuite/libphobos.shared/host.c
+++ b/libphobos/testsuite/libphobos.shared/host.c
@@ -10,6 +10,11 @@ int main(int argc, char* argv[])
void *druntime = dlopen(argv[1], RTLD_LAZY); // load druntime
assert(druntime);
#endif
+#if defined(__DragonFly__)
+ // workaround for Bugzilla 14824
+ void *druntime = dlopen(argv[1], RTLD_LAZY); // load druntime
+ assert(druntime);
+#endif
const size_t pathlen = strrchr(argv[0], '/') - argv[0] + 1;
char *name = malloc(pathlen + sizeof("plugin1.so"));
@@ -56,5 +61,8 @@ int main(int argc, char* argv[])
#if defined(__FreeBSD__)
dlclose(druntime);
#endif
+#if defined(__DragonFly__)
+ dlclose(druntime);
+#endif
return EXIT_SUCCESS;
}
diff --git a/libphobos/testsuite/libphobos.shared/link_mod_collision.d b/libphobos/testsuite/libphobos.shared/link_mod_collision.d
deleted file mode 100644
index 9c3d1c7..0000000
--- a/libphobos/testsuite/libphobos.shared/link_mod_collision.d
+++ /dev/null
@@ -1,5 +0,0 @@
-module lib; // module collides with lib.so
-
-void main()
-{
-}
diff --git a/libphobos/testsuite/libphobos.shared/load.d b/libphobos/testsuite/libphobos.shared/load.d
index 5a2dd01..0d3ffa6 100644
--- a/libphobos/testsuite/libphobos.shared/load.d
+++ b/libphobos/testsuite/libphobos.shared/load.d
@@ -2,7 +2,6 @@ import core.runtime;
import core.stdc.stdio;
import core.stdc.string;
import core.thread;
-
import core.sys.posix.dlfcn;
version (DragonFlyBSD) import core.sys.dragonflybsd.dlfcn : RTLD_NOLOAD;
diff --git a/libphobos/testsuite/libphobos.shared/load_13414.d b/libphobos/testsuite/libphobos.shared/load_13414.d
index f7cbf45..047d507 100644
--- a/libphobos/testsuite/libphobos.shared/load_13414.d
+++ b/libphobos/testsuite/libphobos.shared/load_13414.d
@@ -16,8 +16,17 @@ void runTest(string name)
*cast(void function()*).dlsym(h, "_D9lib_1341420sharedStaticDtorHookOPFZv") = &sharedStaticDtorHook;
Runtime.unloadLibrary(h);
- assert(tlsDtor == 1);
- assert(dtor == 1);
+ version (CRuntime_Musl)
+ {
+ // On Musl, unloadLibrary is a no-op because dlclose is a no-op
+ assert(tlsDtor == 0);
+ assert(dtor == 0);
+ }
+ else
+ {
+ assert(tlsDtor == 1);
+ assert(dtor == 1);
+ }
}
void main(string[] args)
diff --git a/libphobos/testsuite/libphobos.shared/load_mod_collision.d b/libphobos/testsuite/libphobos.shared/load_mod_collision.d
deleted file mode 100644
index 64243d4..0000000
--- a/libphobos/testsuite/libphobos.shared/load_mod_collision.d
+++ /dev/null
@@ -1,14 +0,0 @@
-module lib; // module collides with lib.so
-
-import core.runtime;
-import core.stdc.stdio;
-import core.stdc.string;
-import core.sys.posix.dlfcn;
-
-void main(string[] args)
-{
- auto name = args[0] ~ '\0';
- const pathlen = strrchr(name.ptr, '/') - name.ptr + 1;
- name = name[0 .. pathlen] ~ "lib.so";
- auto lib = Runtime.loadLibrary(name);
-}
diff --git a/libphobos/testsuite/libphobos.thread/external_threads.d b/libphobos/testsuite/libphobos.thread/external_threads.d
new file mode 100644
index 0000000..9c98a3f
--- /dev/null
+++ b/libphobos/testsuite/libphobos.thread/external_threads.d
@@ -0,0 +1,50 @@
+import core.sys.posix.pthread;
+import core.memory;
+import core.thread;
+
+extern (C) void rt_moduleTlsCtor();
+extern (C) void rt_moduleTlsDtor();
+
+extern(C)
+void* entry_point1(void*)
+{
+ // try collecting - GC must ignore this call because this thread
+ // is not registered in runtime
+ GC.collect();
+ return null;
+}
+
+extern(C)
+void* entry_point2(void*)
+{
+ // This thread gets registered in druntime, does some work and gets
+ // unregistered to be cleaned up manually
+ thread_attachThis();
+ rt_moduleTlsCtor();
+
+ auto x = new int[10];
+
+ rt_moduleTlsDtor();
+ thread_detachThis();
+ return null;
+}
+
+void main()
+{
+ // allocate some garbage
+ auto x = new int[1000];
+
+ {
+ pthread_t thread;
+ auto status = pthread_create(&thread, null, &entry_point1, null);
+ assert(status == 0);
+ pthread_join(thread, null);
+ }
+
+ {
+ pthread_t thread;
+ auto status = pthread_create(&thread, null, &entry_point2, null);
+ assert(status == 0);
+ pthread_join(thread, null);
+ }
+}
diff --git a/libphobos/testsuite/libphobos.thread/fiber_guard_page.d b/libphobos/testsuite/libphobos.thread/fiber_guard_page.d
index ca54a19..dbdd0f9 100644
--- a/libphobos/testsuite/libphobos.thread/fiber_guard_page.d
+++ b/libphobos/testsuite/libphobos.thread/fiber_guard_page.d
@@ -4,6 +4,9 @@ import core.thread;
import core.sys.posix.signal;
import core.sys.posix.sys.mman;
+version (LDC) import ldc.attributes;
+else struct optStrategy { string a; }
+
// this should be true for most architectures
// (taken from core.thread)
version (GNU_StackGrowsDown)
@@ -12,6 +15,7 @@ version (GNU_StackGrowsDown)
enum stackSize = MINSIGSTKSZ;
// Simple method that causes a stack overflow
+@optStrategy("none")
void stackMethod()
{
// Over the stack size, so it overflows the stack
diff --git a/libphobos/testsuite/libphobos.thread/join_detach.d b/libphobos/testsuite/libphobos.thread/join_detach.d
new file mode 100644
index 0000000..f151519
--- /dev/null
+++ b/libphobos/testsuite/libphobos.thread/join_detach.d
@@ -0,0 +1,20 @@
+import core.thread;
+import core.sync.semaphore;
+
+__gshared Semaphore sem;
+
+void thread_main ()
+{
+ sem.notify();
+}
+
+void main()
+{
+ auto th = new Thread(&thread_main);
+ sem = new Semaphore();
+ th.start();
+ sem.wait();
+ while (th.isRunning()) {}
+ destroy(th); // force detach
+ th.join();
+}
diff --git a/libphobos/testsuite/libphobos.thread/test_import.d b/libphobos/testsuite/libphobos.thread/test_import.d
new file mode 100644
index 0000000..dfa0487
--- /dev/null
+++ b/libphobos/testsuite/libphobos.thread/test_import.d
@@ -0,0 +1,7 @@
+// https://issues.dlang.org/show_bug.cgi?id=20447
+void main()
+{
+ import core.thread;
+ int[] x;
+ auto b = x.dup;
+}
diff --git a/libphobos/testsuite/libphobos.thread/tlsgc_sections.d b/libphobos/testsuite/libphobos.thread/tlsgc_sections.d
index 1421d92..1bd3f26 100644
--- a/libphobos/testsuite/libphobos.thread/tlsgc_sections.d
+++ b/libphobos/testsuite/libphobos.thread/tlsgc_sections.d
@@ -1,39 +1,70 @@
-final class Class
+import core.memory;
+import core.sync.condition;
+import core.sync.mutex;
+import core.thread;
+
+__gshared Condition g_cond;
+__gshared Mutex g_mutex;
+__gshared int g_step = 0;
+
+class C
{
- // This gets triggered although the instance always stays referenced.
~this()
{
import core.stdc.stdlib;
- abort();
+ abort(); // this gets triggered although the instance always stays referenced
}
}
-Class obj;
+C c;
static this()
{
- obj = new Class;
+ c = new C;
}
static ~this()
{
- // Free without destruction to avoid triggering abort()
import core.memory;
- GC.free(cast(void*)obj);
+ GC.free(cast(void*)c); // free without destruction to avoid triggering abort()
}
-void doit()
+void test()
{
- foreach (i; 0 .. 10_000)
- new ubyte[](100_000);
+ assert(c !is null);
+
+ // notify the main thread of the finished initialization
+ synchronized (g_mutex) g_step = 1;
+ g_cond.notifyAll();
+
+ // wait until the GC collection is done
+ synchronized (g_mutex) {
+ while (g_step != 2)
+ g_cond.wait();
+ }
}
+
void main()
{
- import core.thread;
- auto t = new Thread(&doit);
- t.start();
+ g_mutex = new Mutex;
+ g_cond = new Condition(g_mutex);
+
+ auto th = new Thread(&test);
+ th.start();
+
+ // wait for thread to be fully initialized
+ synchronized (g_mutex) {
+ while (g_step != 1)
+ g_cond.wait();
+ }
+
+ // this causes the other thread's C instance to be reaped with the bug present
+ GC.collect();
+
+ // allow the thread to shut down
+ synchronized (g_mutex) g_step = 2;
+ g_cond.notifyAll();
- // This triggers the GC that frees the still referenced Class instance.
- doit();
+ th.join();
}
diff --git a/libphobos/testsuite/libphobos.thread/tlsstack.d b/libphobos/testsuite/libphobos.thread/tlsstack.d
new file mode 100644
index 0000000..dbd9321
--- /dev/null
+++ b/libphobos/testsuite/libphobos.thread/tlsstack.d
@@ -0,0 +1,38 @@
+module core.thread.test; // needs access to getStackTop()/getStackBottom()
+
+import core.stdc.stdio;
+import core.thread;
+
+ubyte[16384] data;
+
+void showThreadInfo() nothrow
+{
+ try
+ {
+ auto top = getStackTop();
+ auto bottom = getStackBottom();
+ printf("tlsdata: %p\n", data.ptr);
+ printf("stack top: %p\n", getStackTop());
+ printf("stack bottom:%p\n", getStackBottom());
+ printf("used stack: %lld\n", cast(ulong)(bottom - top));
+ }
+ catch(Exception e)
+ {
+ assert(false, e.msg);
+ }
+}
+
+void main()
+{
+ printf("### main\n");
+ showThreadInfo();
+
+ printf("### thread\n");
+ auto th = new Thread(&showThreadInfo, 16384);
+ th.start();
+ th.join();
+
+ printf("### lowlevel thread\n");
+ auto llth = createLowLevelThread(() { showThreadInfo(); });
+ joinLowLevelThread(llth);
+}
diff --git a/libphobos/testsuite/libphobos.typeinfo/enum_.d b/libphobos/testsuite/libphobos.typeinfo/enum_.d
new file mode 100644
index 0000000..58cfbe3
--- /dev/null
+++ b/libphobos/testsuite/libphobos.typeinfo/enum_.d
@@ -0,0 +1,21 @@
+// https://issues.dlang.org/show_bug.cgi?id=21441
+
+int dtorCount;
+int postblitCount;
+
+struct S
+{
+ this(this) { ++postblitCount; }
+ ~this() { ++dtorCount; }
+}
+
+enum E : S { _ = S.init }
+
+void main()
+{
+ E e;
+ typeid(e).destroy(&e);
+ assert(dtorCount == 1);
+ typeid(e).postblit(&e);
+ assert(postblitCount == 1);
+}
diff --git a/libphobos/testsuite/libphobos.typeinfo/isbaseof.d b/libphobos/testsuite/libphobos.typeinfo/isbaseof.d
new file mode 100644
index 0000000..26dd5a6
--- /dev/null
+++ b/libphobos/testsuite/libphobos.typeinfo/isbaseof.d
@@ -0,0 +1,46 @@
+// https://issues.dlang.org/show_bug.cgi?id=20178
+
+interface I {}
+interface J : I {}
+interface K(T) {}
+class C1 : I {}
+class C2 : C1 {}
+class C3 : J {}
+class C4(T) : C3, K!T {}
+class C5(T) : C4!T {}
+
+void main() @nogc nothrow pure @safe
+{
+ assert(typeid(C1).isBaseOf(typeid(C1)));
+ assert(typeid(C1).isBaseOf(typeid(C2)));
+
+ assert(!typeid(C2).isBaseOf(typeid(C1)));
+ assert(typeid(C2).isBaseOf(typeid(C2)));
+
+ assert(!typeid(C1).isBaseOf(typeid(Object)));
+ assert(!typeid(C2).isBaseOf(typeid(Object)));
+ assert(typeid(Object).isBaseOf(typeid(C1)));
+ assert(typeid(Object).isBaseOf(typeid(C2)));
+
+ assert(typeid(I).isBaseOf(typeid(I)));
+ assert(typeid(I).isBaseOf(typeid(J)));
+ assert(typeid(I).isBaseOf(typeid(C1)));
+ assert(typeid(I).isBaseOf(typeid(C2)));
+ assert(typeid(I).isBaseOf(typeid(C3)));
+ assert(!typeid(I).isBaseOf(typeid(Object)));
+
+ assert(!typeid(J).isBaseOf(typeid(I)));
+ assert(typeid(J).isBaseOf(typeid(J)));
+ assert(!typeid(J).isBaseOf(typeid(C1)));
+ assert(!typeid(J).isBaseOf(typeid(C2)));
+ assert(typeid(J).isBaseOf(typeid(C3)));
+ assert(!typeid(J).isBaseOf(typeid(Object)));
+
+ assert(typeid(C4!int).isBaseOf(typeid(C5!int)));
+ assert(typeid(K!int).isBaseOf(typeid(C5!int)));
+ assert(!typeid(C4!Object).isBaseOf(typeid(C5!int)));
+ assert(!typeid(K!Object).isBaseOf(typeid(C5!int)));
+
+ static assert(!__traits(compiles, TypeInfo.init.isBaseOf(typeid(C1))));
+ static assert(!__traits(compiles, typeid(C1).isBaseOf(TypeInfo.init)));
+}
diff --git a/libphobos/testsuite/libphobos.unittest/customhandler.d b/libphobos/testsuite/libphobos.unittest/customhandler.d
new file mode 100644
index 0000000..f5a0435
--- /dev/null
+++ b/libphobos/testsuite/libphobos.unittest/customhandler.d
@@ -0,0 +1,21 @@
+import core.runtime;
+
+UnitTestResult customModuleUnitTester()
+{
+ version(GoodTests) return UnitTestResult(100, 100, false, true);
+ version(FailedTests) return UnitTestResult(100, 0, false, true);
+ version(NoTests) return UnitTestResult(0, 0, true, false);
+ version(FailNoPrintout) return UnitTestResult(100, 0, false, false);
+ version(PassNoPrintout) return UnitTestResult(100, 100, false, false);
+}
+
+shared static this()
+{
+ Runtime.extendedModuleUnitTester = &customModuleUnitTester;
+}
+
+void main()
+{
+ import core.stdc.stdio;
+ fprintf(stderr, "main\n");
+}
diff --git a/libphobos/testsuite/libphobos.unittest/unittest.exp b/libphobos/testsuite/libphobos.unittest/unittest.exp
new file mode 100644
index 0000000..ba2fc6e
--- /dev/null
+++ b/libphobos/testsuite/libphobos.unittest/unittest.exp
@@ -0,0 +1,53 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+load_lib libphobos-dg.exp
+
+set dg-output-text [list]
+
+# Arguments to pass to the compiler, expected output, and return code.
+set unit_test_list [list \
+ { "-fversion=PassNoPrintout" 0 } \
+ { "-fversion=GoodTests" 0 } \
+ { "-fversion=FailNoPrintout" 1 } \
+ { "-fversion=FailedTests" 1 } \
+ { "-fversion=NoTests" 0 } \
+]
+
+# Initialize dg.
+dg-init
+
+# Gather a list of all tests.
+set tests [lsort [find $srcdir/$subdir *.d]]
+
+# Main loop.
+foreach unit_test $unit_test_list {
+ # The version flags to build the program with.
+ set test_flags [lindex $unit_test 0]
+
+ # Whether the program is expected to fail.
+ set expected_fail [lindex $unit_test 1]
+
+ foreach test $tests {
+ set shouldfail $expected_fail
+ dg-test $test "" $test_flags
+ }
+
+ set shouldfail 0
+}
+
+# All done.
+dg-finish
diff --git a/libphobos/testsuite/testsuite_flags.in b/libphobos/testsuite/testsuite_flags.in
index bafd5ad4..93bf7cb 100755
--- a/libphobos/testsuite/testsuite_flags.in
+++ b/libphobos/testsuite/testsuite_flags.in
@@ -29,7 +29,7 @@ case ${query} in
--gdcflags)
GDCFLAGS_default="-fmessage-length=0 -fno-show-column"
GDCFLAGS_config="@WARN_DFLAGS@ @GDCFLAGS@ @CET_DFLAGS@
- @phobos_compiler_shared_flag@ -fno-release -funittest"
+ @phobos_compiler_shared_flag@ -fpreview=dip1000 -fno-release -funittest"
echo ${GDCFLAGS_default} ${GDCFLAGS_config}
;;
--gdcpaths)